From c23f8a4be62ef9f223af6306a9be26bf96d6de59 Mon Sep 17 00:00:00 2001 From: LoaD Accumulator Date: Wed, 4 Oct 2023 15:02:38 -0400 Subject: [PATCH 01/37] [FIX] Fix issue related to TLS (#1) The Makefile didn't properly set TLS_IMPL, effectively causing no TLS implementation to be put in. Co-authored-by: LoaD Accumulator Reviewed-on: https://git.telodendria.io/Telodendria/Cytoplasm/pulls/1 Co-authored-by: LoaD Accumulator Co-committed-by: LoaD Accumulator --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 65df084..3f05817 100755 --- a/configure +++ b/configure @@ -37,11 +37,11 @@ echo "Ran with arguments: $SCRIPT_ARGS" for arg in $SCRIPT_ARGS; do case "$arg" in --with-openssl) - TLS_IMPL="OPENSSL" + TLS_IMPL="TLS_OPENSSL" TLS_LIBS="-lcrypto -lssl" ;; --with-libressl) - TLS_IMPL="LIBRESSL" + TLS_IMPL="TLS_LIBRESSL" TLS_LIBS="-ltls -lcrypto -lssl" ;; --disable-tls) From e69769d4d2ab506955080a9b13de5e5bbc344611 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 11:29:15 -0400 Subject: [PATCH 02/37] Update configure --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index 3f05817..9faa034 100755 --- a/configure +++ b/configure @@ -45,6 +45,7 @@ for arg in $SCRIPT_ARGS; do TLS_LIBS="-ltls -lcrypto -lssl" ;; --disable-tls) + TLS_IMPL="" TLS_LIBS="" ;; --prefix=*) From 3a683dbb70d74e8f515ab32a2ccc48ea24c0a2b9 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 12:10:41 -0400 Subject: [PATCH 03/37] Fix includes in headers. These are installed to the system and some compilers may not find the headers in the current directory if we don't do this, even though according to the C standard, either should work. --- src/include/Args.h | 2 +- src/include/Cron.h | 2 +- src/include/Db.h | 4 ++-- src/include/HashMap.h | 2 +- src/include/HeaderParser.h | 4 ++-- src/include/Http.h | 4 ++-- src/include/HttpClient.h | 4 ++-- src/include/HttpRouter.h | 2 +- src/include/HttpServer.h | 7 +++---- src/include/Int64.h | 4 ++-- src/include/Json.h | 8 ++++---- src/include/Log.h | 2 +- src/include/Runtime.h | 2 -- src/include/Str.h | 2 +- src/include/Stream.h | 2 +- src/include/Tls.h | 2 +- src/include/UInt64.h | 2 +- src/include/Util.h | 4 ++-- 18 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/include/Args.h b/src/include/Args.h index 3108de3..2161c1b 100644 --- a/src/include/Args.h +++ b/src/include/Args.h @@ -38,7 +38,7 @@ * provide the standard command line interface. */ -#include +#include "Array.h" /** * All state is stored in this structure, instead of global diff --git a/src/include/Cron.h b/src/include/Cron.h index e78900d..23053c6 100644 --- a/src/include/Cron.h +++ b/src/include/Cron.h @@ -56,7 +56,7 @@ * by any means. */ -#include +#include "Int.h" /** * All functions defined here operate on a structure opaque to the diff --git a/src/include/Db.h b/src/include/Db.h index 618a2e2..da98a39 100644 --- a/src/include/Db.h +++ b/src/include/Db.h @@ -38,8 +38,8 @@ #include -#include -#include +#include "HashMap.h" +#include "Array.h" /** * All functions in this API operate on a database structure that is diff --git a/src/include/HashMap.h b/src/include/HashMap.h index 1359400..f0ee7f3 100644 --- a/src/include/HashMap.h +++ b/src/include/HashMap.h @@ -46,7 +46,7 @@ #include -#include +#include "Array.h" /** * These functions operate on an opaque structure, which the caller diff --git a/src/include/HeaderParser.h b/src/include/HeaderParser.h index ffb3d0b..52d8e33 100644 --- a/src/include/HeaderParser.h +++ b/src/include/HeaderParser.h @@ -41,8 +41,8 @@ * for example usage of this parser. */ -#include -#include +#include "Stream.h" +#include "Array.h" #define HEADER_EXPR_MAX 4096 diff --git a/src/include/Http.h b/src/include/Http.h index d2de020..37875d8 100644 --- a/src/include/Http.h +++ b/src/include/Http.h @@ -42,8 +42,8 @@ #include -#include -#include +#include "HashMap.h" +#include "Stream.h" #define HTTP_FLAG_NONE 0 #define HTTP_FLAG_TLS (1 << 0) diff --git a/src/include/HttpClient.h b/src/include/HttpClient.h index f757041..28fe3c2 100644 --- a/src/include/HttpClient.h +++ b/src/include/HttpClient.h @@ -39,8 +39,8 @@ #include -#include -#include +#include "HashMap.h" +#include "Http.h" /** * A server response is represented by a client context. It is diff --git a/src/include/HttpRouter.h b/src/include/HttpRouter.h index 6816178..a0950b0 100644 --- a/src/include/HttpRouter.h +++ b/src/include/HttpRouter.h @@ -38,7 +38,7 @@ * handler functions. */ -#include +#include "Array.h" /** * The router structure is opaque and thus managed entirely by the diff --git a/src/include/HttpServer.h b/src/include/HttpServer.h index f8e449a..78ef2f8 100644 --- a/src/include/HttpServer.h +++ b/src/include/HttpServer.h @@ -46,12 +46,11 @@ * closely resembles Java. */ -#include - #include -#include -#include +#include "Http.h" +#include "HashMap.h" +#include "Stream.h" /** * The functions on this API operate on an opaque structure. diff --git a/src/include/Int64.h b/src/include/Int64.h index 08083c1..e380ab4 100644 --- a/src/include/Int64.h +++ b/src/include/Int64.h @@ -64,8 +64,8 @@ * @ignore-typedefs */ -#include -#include +#include "Int.h" +#include "UInt64.h" #include diff --git a/src/include/Json.h b/src/include/Json.h index 4185260..cc4a63d 100644 --- a/src/include/Json.h +++ b/src/include/Json.h @@ -68,10 +68,10 @@ * behavior. */ -#include -#include -#include -#include +#include "HashMap.h" +#include "Array.h" +#include "Stream.h" +#include "Int64.h" #include #include diff --git a/src/include/Log.h b/src/include/Log.h index d0300ca..1567b6e 100644 --- a/src/include/Log.h +++ b/src/include/Log.h @@ -42,7 +42,7 @@ #include #include -#include +#include "Stream.h" #define LOG_FLAG_COLOR (1 << 0) #define LOG_FLAG_SYSLOG (1 << 1) diff --git a/src/include/Runtime.h b/src/include/Runtime.h index 6e13b6a..f23a1ba 100644 --- a/src/include/Runtime.h +++ b/src/include/Runtime.h @@ -37,8 +37,6 @@ * the runtime stub needs to know their definitions. */ -#include - /** * Write a memory report to a file in the current directory, using * the provided program arguments, including the program name that diff --git a/src/include/Str.h b/src/include/Str.h index 714b8d8..cae9062 100644 --- a/src/include/Str.h +++ b/src/include/Str.h @@ -39,7 +39,7 @@ * is a standard library header. */ -#include +#include "Int.h" #include diff --git a/src/include/Stream.h b/src/include/Stream.h index 3ddacc6..7c6a1a5 100644 --- a/src/include/Stream.h +++ b/src/include/Stream.h @@ -36,7 +36,7 @@ * C library and offering some more convenience features. */ -#include +#include "Io.h" #include diff --git a/src/include/Tls.h b/src/include/Tls.h index 4407ed0..8314f7d 100644 --- a/src/include/Tls.h +++ b/src/include/Tls.h @@ -46,7 +46,7 @@ * .El */ -#include +#include "Stream.h" #define TLS_LIBRESSL 2 #define TLS_OPENSSL 3 diff --git a/src/include/UInt64.h b/src/include/UInt64.h index 51cc30c..c16fc22 100644 --- a/src/include/UInt64.h +++ b/src/include/UInt64.h @@ -64,7 +64,7 @@ * @ignore-typedefs */ -#include +#include "Int.h" #include diff --git a/src/include/Util.h b/src/include/Util.h index d6c3830..e7bef57 100644 --- a/src/include/Util.h +++ b/src/include/Util.h @@ -42,8 +42,8 @@ #include #include -#include -#include +#include "Stream.h" +#include "UInt64.h" /** * Get the current timestamp in milliseconds since the Unix epoch. This From 7c1173eef88413a63aad2e7aa69ab2d9b1654803 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 12:21:14 -0400 Subject: [PATCH 04/37] Install tools to system. Note that int64 and uint64 should probably be removed. --- configure | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure b/configure index 9faa034..d0e1a5a 100755 --- a/configure +++ b/configure @@ -169,6 +169,13 @@ install_man() { echo "${TAB}install -D \"$src\" \"$out\"" } +install_tool() { + src=${OUT}/bin/$(basename "$1" .c) + out="$2" + + echo "${TAB}install -D \"$src\" \"$out\"" +} + uninstall_out() { src="$1" out="$2" @@ -221,12 +228,14 @@ ${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.a \$(PREFIX)/lib/lib${LIB_NAME}.a ${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.so \$(PREFIX)/lib/lib${LIB_NAME}.so $(collect ${INCLUDE}/ '' '' \$\(PREFIX\)/include/${LIB_NAME}/ install_out) $(collect ${INCLUDE}/ .h .3 \$\(PREFIX\)/man/man3/${LIB_NAME}- install_man) +$(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ install_tool) uninstall: ${TAB}rm -r \$(PREFIX)/lib/${LIB_NAME}.* ${TAB}rm -r \$(PREFIX)/lib/lib${LIB_NAME}.* ${TAB}rm -r \$(PREFIX)/include/${LIB_NAME} ${TAB}rm -r \$(PREFIX)/man/man3/${LIB_NAME}-* +$(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ uninstall_out) clean: ${TAB}rm -r "${BUILD}" "${OUT}" From 2714a822b0cc0235d61a8b277522683c97ff7c20 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 13:43:35 -0400 Subject: [PATCH 05/37] j2s now generates the proper includes. --- tools/j2s.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/j2s.c b/tools/j2s.c index 2e6b5b4..9a85a00 100644 --- a/tools/j2s.c +++ b/tools/j2s.c @@ -441,9 +441,9 @@ Main(Array * args) StreamPrintf(headerFile, "#ifndef %s\n", guard); StreamPrintf(headerFile, "#define %s\n\n", guard); - StreamPrintf(headerFile, "#include \n"); - StreamPrintf(headerFile, "#include \n"); - StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); StreamPutc(headerFile, '\n'); @@ -583,9 +583,9 @@ Main(Array * args) StreamPrintf(implFile, "/* Generated by j2s */\n\n"); StreamPrintf(implFile, "#include <%s>\n\n", headerName); - StreamPrintf(implFile, "#include \n"); - StreamPrintf(implFile, "#include \n"); - StreamPrintf(implFile, "#include \n"); + StreamPrintf(implFile, "#include \n"); + StreamPrintf(implFile, "#include \n"); + StreamPrintf(implFile, "#include \n"); StreamPutc(implFile, '\n'); From 2ea041d99d9f599469ce3e6dbe6705af678413f6 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 14:11:22 -0400 Subject: [PATCH 06/37] main() is already included in the library. The runtime stub doesn't need to be a separate object. --- configure | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/configure b/configure index d0e1a5a..94d3ff2 100755 --- a/configure +++ b/configure @@ -18,7 +18,7 @@ LIBS="-lm -pthread" # Set default args for all platforms -SCRIPT_ARGS="--lib-rtstub=RtStub --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@" +SCRIPT_ARGS="--prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@" # Set platform specific args case "$(uname)" in @@ -74,9 +74,6 @@ for arg in $SCRIPT_ARGS; do --disable-debug) DEBUG="" ;; - --lib-rtstub=*) - STUB=$(echo "$arg" | cut -d '=' -f 2-) - ;; --static) STATIC="-static -Wl,-static" ;; @@ -141,9 +138,9 @@ compile_bin() { src="$1" out="$2" - echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${OUT}/lib/${LIB_NAME}.o ${src}" + echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${src}" echo "${TAB}@mkdir -p ${OUT}/bin" - echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" ${OUT}/lib/${LIB_NAME}.o -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME} ${STATIC}" + echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME} ${STATIC}" } compile_doc() { @@ -220,10 +217,9 @@ ${TAB} diff -u -p - "LICENSE.txt" | \\ ${TAB} patch "\$\$src" | grep -v "^Hmm"; \\ ${TAB}done -${LIB_NAME}: ${OUT}/lib/${LIB_NAME}.o ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so +${LIB_NAME}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so install: ${LIB_NAME} -${TAB}install -D ${OUT}/lib/${LIB_NAME}.o \$(PREFIX)/lib/${LIB_NAME}.o ${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.a \$(PREFIX)/lib/lib${LIB_NAME}.a ${TAB}install -D ${OUT}/lib/lib${LIB_NAME}.so \$(PREFIX)/lib/lib${LIB_NAME}.so $(collect ${INCLUDE}/ '' '' \$\(PREFIX\)/include/${LIB_NAME}/ install_out) @@ -231,7 +227,6 @@ $(collect ${INCLUDE}/ .h .3 \$\(PREFIX\)/man/man3/${LIB_NAME}- install_man) $(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ install_tool) uninstall: -${TAB}rm -r \$(PREFIX)/lib/${LIB_NAME}.* ${TAB}rm -r \$(PREFIX)/lib/lib${LIB_NAME}.* ${TAB}rm -r \$(PREFIX)/include/${LIB_NAME} ${TAB}rm -r \$(PREFIX)/man/man3/${LIB_NAME}-* @@ -240,10 +235,6 @@ $(collect ${TOOLS}/ '.c' '' \$\(PREFIX\)/bin/ uninstall_out) clean: ${TAB}rm -r "${BUILD}" "${OUT}" -${OUT}/lib/${LIB_NAME}.o: ${BUILD}/${STUB}.o -${TAB}@mkdir -p ${OUT}/lib -${TAB}cp ${BUILD}/${STUB}.o ${OUT}/lib/${LIB_NAME}.o - ${OUT}/lib/lib${LIB_NAME}.a: ${OBJS} ${TAB}@mkdir -p ${OUT}/lib ${TAB}\$(AR) rcs ${OUT}/lib/lib${LIB_NAME}.a ${OBJS} From 51898d5bac782d083468b8cf60f966e739e0e81e Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 15:31:49 -0400 Subject: [PATCH 07/37] Update README.md --- README.md | 56 ++++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8a1e59f..416e962 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Cytoplasm (libcytoplasm) -Cytoplasm is a general-purpose C library and runtime stub for creating high-level (particularly networked and multi-threaded) C applications. It allows applications to take advantage of the speed, flexibility, and simplicity of the C programming language, while providing helpful code to perform various complex tasks. Cytoplasm provides high-level data structures, a basic logging facility, an HTTP client and server, and more. +Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications. It allows applications to take advantage of the speed, flexibility, and simplicity of the C programming language, while providing helpful code to allow applications to perform various complex tasks with minimal effort. Cytoplasm provides high-level data structures, a basic logging facility, an HTTP client and server, and more. It also reports memory leaks, which can aid in debugging. -Cytoplasm aims not to only do one thing well, but to do many things good enough. The primary target of Cytoplasm is simple, yet higher level C applications that have to perform relatively complex tasks, but don't want to pull in a large number of dependencies. +Cytoplasm aims not to only do one thing well, but to do many things good enough. This is in contrast to other libraries, which only do one thing and thus require the developer to pull in many different libraries. The primary target of Cytoplasm is simple yet higher level C applications that have to perform relatively complex tasks, but don't want to depend on a large number of dependencies. Cytoplasm is extremely opinionated on the way programs using it are written. It strives to create a comprehensive and tightly-integrated programming environment, while also maintaining C programming correctness. It doesn't do any macro magic or make C look like anything other than C. It is written entirely in C89, and depends only on a POSIX environment. This differentiates it from other general-purpose libraries that often require modern compilers and non-standard language and environment features. Cytoplasm is intended to be extremely portable and simple, while still providing some of the functionality expected in higher-level programming languages in a platform-agnostic manner. In the case of TLS, Cytoplasm wraps low-level TLS libraries to offer a single, unified interface to TLS so that programs do not have to care about the underlying implementation. -Cytoplasm is probably not suitable for embedded programming. It makes liberal use of the heap, and while data structures are designed to conserve memory where possible and practical, minimal memory usage is not really a design goal for Cytoplasm, although Cytoplasm takes care not to use any more memory than it absolutely needs. Cytoplasm also wraps a few standard libraries with additional logic and checking. While this ensures better runtime safetly, this inevitably adds a little overhead. +Cytoplasm is probably not suitable for embedded programming. It makes liberal use of the heap, and while data structures are designed to conserve memory where possible and practical, minimal memory usage is not really a design goal for Cytoplasm, although Cytoplasm takes care not to use any more memory than it absolutely needs. Cytoplasm also wraps a few standard libraries with additional logic and checking. While this ensures better runtime safety, this inevitably adds a little overhead, which may be unsuitable for time- or space-critical tasks. -Originally a part of Telodendria (https://telodendria.io), a Matrix homeserver written in C, Cytoplasm was split off into its own project due to the desire of some Telodendria developers to use Telodendria's code in other projects. Cytoplasm is still a Telodendria project, and is maintained along side of Telodendria itself, even living in the same CVS module, but it is designed specifically to be distributed and used totally independent of Telodendria. +Originally a part of Telodendria (https://telodendria.io), a Matrix homeserver written in C, Cytoplasm was split off into its own project due to the desire of some Telodendria developers to use Telodendria's code in other projects. Cytoplasm is still an official Telodendria project, but it is designed specifically to be distributed and used totally independent of Telodendria. -The name "Cytoplasm" was chosen for a few reasons. It plays off the precedent set up by the Matrix organization in naming projects after the parts of a neuron. It also speaks to the function of Cytoplasm. The cytoplasm of a cell is the supporting material. It is what gives the cell its shape, and it facilitates the movement of materials to the other cell parts. Likewise, Cytoplasm aims to provide a support mechanism for C applications that have to perform complex tasks. +The name "Cytoplasm" was chosen for a few reasons. It plays off the precedent set up by the Matrix organization in naming projects after the parts of a neuron. It also speaks to the function of Cytoplasm. The cytoplasm of a cell is the supporting material. It is what gives the cell its shape, and it facilitates the movement of materials to the other cell parts. Likewise, Cytoplasm aims to provide a support mechanism for C applications that have to perform complex tasks beyond what the C standard library provides. Cytoplasm also starts with a C, which I think is a nice touch for C libraries. It's also fun to say and unique enough that searching for "libcytoplasm" should bring you to this project and not some other one. @@ -18,14 +18,17 @@ Cytoplasm also starts with a C, which I think is a nice touch for C libraries. I If your operating system or software distribution provides a pre-built package of Cytoplasm, you should prefer to use that instead of building it from source. -Cytoplasm aims to have zero dependencies beyond what is mandated by POSIX. You only need the standard math and pthread libraries to build it. TLS support can optionally be enabled by setting the TLS_IMPL environment variable. The supported TLS implementations are as follows: +Cytoplasm aims to have zero dependencies beyond what is mandated by POSIX. You only need the standard math and pthread libraries to build it. TLS support can optionally be enabled with the configuration script. The supported TLS implementations are as follows: - OpenSSL - LibreSSL -If TLS support is not enabled, all APIs that use it should fall back to non-TLS behavior in a sensible manner. For example, if TLS support is not enabled, then the HTTP client API will simply return an error if a TLS connection is requested. Cytoplasm uses a custom build script instead of Make, for the sake of portability. To build everything, just run the script: +If TLS support is not enabled, all APIs that use it should fall back to non-TLS behavior in a sensible manner. For example, if TLS support is not enabled, then the HTTP client API will simply return an error if a TLS connection is requested. Cytoplasm uses the standard C library build procedure. Just run these commands: - $ sh make.sh +``` +./configure +make +``` This will produce the following out/ directory: @@ -33,46 +36,39 @@ This will produce the following out/ directory: out/ lib/ libcytoplasm.so - The Cytoplasm shared library. - libcytoplasm.a - The Cytoplasm static library. - cytoplasm.o - The Cytoplasm runtime stub. - bin/ - hdoc - The documentation generator tool. + libcytoplasm.a - The Cytoplasm static archive. + bin/ - A few useful tools build with Cytoplasm. man/ - All Cytoplasm API documentation. ``` +You can also run `make install` as `root` to install Cytoplasm to the system. This will install the libraries, tools, and `man` pages. + ## Usage -Cytoplasm provides the typical .so and .a files, which can be used to link programs with it in the usual way. However, Cytoplasm also provides a minimal runtime environment that is intended to be used with the library. As such, it also provides a runtime stub, which is intended to be linked in with programs using Cytoplasm. This stub is responsible for setting up and tearing down some Cytoplasm APIs. While it isn't required by any means, it makes Cytoplasm a lot easier to use for programmers by abstracting out all of the common logic that most programs will want to use. +Cytoplasm provides the typical .so and .a files, which can be used to link programs with it in the usual way. Somewhat *unusually* for C libraries, however, it provides its own `main()` function, so programs written with Cytoplasm provide `Main()` instead, which is called by Cytoplasm. Cytoplasm works this way because it needs to perform some setup logic before user code runs and some teardown logic after user code returns. Here is the canonical Hello World written with Cytoplasm: ```c - #include + #include int Main(void) { - Log(LOG_INFO, "Hello World!"); - return 0; - } + Log(LOG_INFO, "Hello World!"); + return 0; + } ``` -If this file is Hello.c, then you can compile it by doing something like this: +If this file is `Hello.c`, then you can compile it by doing this: - $ cc -o hello Hello.c cytoplasm.o -lcytoplasm + $ cc -o hello Hello.c -lCytoplasm -This command assumes that the runtime stub resides in the current working directory, and that libcytoplasm.so is in your library path. If you're using the version of Cytoplasm installed by your operating system or software distribution, consult the documentation for the location of the runtime stub. It may be located in /usr/local/libexec or some other similar location. If you've built Cytoplasm from source and wish to link to it from there, you may wish to do something like this: - - $ export CYTOPLASM=/path/to/Cytoplasm/out/lib - $ cc -o hello Hello.c "${CYTOPLASM}/cytoplasm.o" \ - "-L${CYTOPLASM}" -lcytoplasm - -As you may have noticed, C programs using Cytoplasm's runtime stub don't write the main() function. Instead, they use Main(). The main() function is provided by the runtime stub. The full form of Main() expected by the stub is as follows: +The full form of Main() expected by the stub is as follows: ```c - int Main(Array *args, HashMap *env); + int Main(Array *args, HashMap *env); ``` -The first argument is a Cytoplasm array of the command line arguments, and the second is a Cytoplasm hash map of environment variables. Most linkers will let programs omit the env argument, or both arguments if you don't need either. The return value of Main() is returned to the operating system. - -Note that both arguments to Main may be treated like any other array or hash map. However, do not invoke ArrayFree() or HashMapFree() on the passed pointers, because memory is cleaned up after Main() returns. +The first argument is a Cytoplasm array of the command line arguments, and the second is a Cytoplasm hash map of environment variables. Most linkers will let programs omit the `env` argument, or both arguments if you don't need either. The return value of `Main()` is returned to the operating system, as would be expected. +Note that both arguments to Main may be treated like any other Cytoplasm array or hash map. However, do not invoke `ArrayFree()` or `HashMapFree()` on the passed pointers, because memory is cleaned up after `Main()` returns. From cced0ad883e6b02fa5f2000adacb3b4b462c7ce8 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 30 Oct 2023 14:41:58 -0400 Subject: [PATCH 08/37] Closes #3 --- configure | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 94d3ff2..bdb915b 100755 --- a/configure +++ b/configure @@ -147,9 +147,13 @@ compile_doc() { src="$1" out="$2" + if [ -z "${STATIC}" ]; then + pref="LD_LIBRARY_PATH=${OUT}/lib " + fi + echo "${out}: ${OUT}/bin/hdoc ${src}" echo "${TAB}@mkdir -p ${OUT}/man/man3" - echo "${TAB}${OUT}/bin/hdoc -D \"Os=${LIB_NAME}\" -i \"${src}\" -o \"${out}\"" + echo "${TAB}${pref}${OUT}/bin/hdoc -D \"Os=${LIB_NAME}\" -i \"${src}\" -o \"${out}\"" } install_out() { From 75ecb2272491ca86846aaf34d283f3310dab0fab Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 08:28:35 -0400 Subject: [PATCH 09/37] Remove int64 and uint64; add http. --- tools/http.c | 260 +++++++++++++++++++++++++++++++++++++++++++++++++ tools/int64.c | 145 --------------------------- tools/uint64.c | 119 ---------------------- 3 files changed, 260 insertions(+), 264 deletions(-) create mode 100644 tools/http.c delete mode 100644 tools/int64.c delete mode 100644 tools/uint64.c diff --git a/tools/http.c b/tools/http.c new file mode 100644 index 0000000..0b32b74 --- /dev/null +++ b/tools/http.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * + * 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 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FLAG_HEADERS (1 << 0) + +static void +usage(char *prog) +{ + StreamPrintf(StreamStderr(), "Usage: %s [-i -X method -H header -d data] url\n", prog); +} + +int +Main(Array * args) +{ + HttpClientContext *cx = NULL; + HttpStatus res; + HttpRequestMethod method = HTTP_GET; + Uri *uri = NULL; + char *data = NULL; + + HashMap *requestHeaders = HashMapCreate(); + char *key; + char *val; + + ArgParseState arg; + int flags = 0; + int requestFlags = HTTP_FLAG_NONE; + + int ch; + int ret = 1; + + ArgParseStateInit(&arg); + while ((ch = ArgParse(&arg, args, "iH:X:d:")) != -1) + { + switch (ch) + { + case 'i': + flags |= FLAG_HEADERS; + break; + case 'X': + method = HttpRequestMethodFromString(arg.optArg); + if (!method) + { + StreamPrintf(StreamStderr(), "Unknown request method: %s\n", arg.optArg); + return 1; + } + break; + case 'H': + key = arg.optArg; + val = arg.optArg; + + while (*val && *val != ':') + { + val++; + } + + *val = '\0'; + val++; + + while (*val && isspace((unsigned char) *val)) + { + val++; + } + + HashMapSet(requestHeaders, key, StrDuplicate(val)); + break; + case 'd': + data = arg.optArg; + break; + default: + usage(ArrayGet(args, 0)); + goto finish; + } + } + + if (ArraySize(args) - arg.optInd < 1) + { + usage(ArrayGet(args, 0)); + goto finish; + } + + uri = UriParse(ArrayGet(args, arg.optInd)); + if (!uri) + { + StreamPrintf(StreamStderr(), "Failed to parse URI: %s\n", ArrayGet(args, arg.optInd)); + goto finish; + } + + if (!uri->port) + { + if (StrEquals(uri->proto, "https")) + { + uri->port = 443; + } + else if (StrEquals(uri->proto, "http")) + { + uri->port = 80; + } + } + + if (!uri->port) + { + StreamPrintf(StreamStderr(), "Unknown protocol: %s\n", uri->proto); + goto finish; + } + + if (StrEquals(uri->proto, "https")) + { + requestFlags |= HTTP_FLAG_TLS; + } + + cx = HttpRequest(method, requestFlags, uri->port, uri->host, uri->path); + + if (!cx) + { + StreamPuts(StreamStderr(), "Failed to connect.\n"); + goto finish; + } + + while (HashMapIterate(requestHeaders, &key, (void **) &val)) + { + HttpRequestHeader(cx, key, val); + Free(val); + } + + if (data) + { + if (*data == '@') + { + Stream *in; + int len; + + data++; + + if (StrEquals(data, "-")) + { + in = StreamStdin(); + } + else + { + in = StreamOpen(data, "r"); + } + + if (!in) + { + StreamPrintf(StreamStderr(), "%s: %s\n", data, strerror(errno)); + goto finish; + } + + len = StreamSeek(in, 0, SEEK_END); + if (len > -1) + { + char *lenStr; + int nBytes; + + StreamSeek(in, 0, SEEK_SET); + nBytes = snprintf(NULL, 0, "%d", len); + + lenStr = Malloc(nBytes + 1); + snprintf(lenStr, nBytes + 1, "%d", len); + + HttpRequestHeader(cx, "Content-Length", lenStr); + Free(lenStr); + } + + HttpRequestSendHeaders(cx); + StreamCopy(in, HttpClientStream(cx)); + if (in != StreamStdin()) + { + StreamClose(in); + } + } + else + { + char *lenStr; + int len = strlen(data); + int nBytes = snprintf(NULL, 0, "%d", len); + + lenStr = Malloc(nBytes + 1); + snprintf(lenStr, nBytes + 1, "%d", len); + + HttpRequestHeader(cx, "Content-Length", lenStr); + Free(lenStr); + HttpRequestSendHeaders(cx); + StreamPuts(HttpClientStream(cx), data); + } + } + else + { + HttpRequestSendHeaders(cx); + } + + res = HttpRequestSend(cx); + + if (!res) + { + StreamPuts(StreamStderr(), "Failed to send request.\n"); + goto finish; + } + + if (flags & FLAG_HEADERS) + { + HashMap *responseHeaders = HttpResponseHeaders(cx); + + StreamPrintf(StreamStdout(), "HTTP/1.0 %d %s\n", res, HttpStatusToString(res)); + + while (HashMapIterate(responseHeaders, &key, (void **) &val)) + { + StreamPrintf(StreamStdout(), "%s: %s\n", key, val); + } + + StreamPutc(StreamStdout(), '\n'); + } + + StreamCopy(HttpClientStream(cx), StreamStdout()); + + ret = !(res == HTTP_OK); + +finish: + HashMapFree(requestHeaders); + + HttpClientContextFree(cx); + UriFree(uri); + + return ret; +} diff --git a/tools/int64.c b/tools/int64.c deleted file mode 100644 index fb9c5cf..0000000 --- a/tools/int64.c +++ /dev/null @@ -1,145 +0,0 @@ -#include - -#include - -/* AssertEquals(actual, expected) */ -int -AssertEquals(char *msg, Int64 x, Int64 y) -{ - if (!Int64Eq(x, y)) - { - Log(LOG_ERR, "%s: Expected 0x%X 0x%X, got 0x%X 0x%X", msg, - Int64High(y), Int64Low(y), - Int64High(x), Int64Low(x)); - - return 0; - } - - return 1; -} - -int -Main(void) -{ - Int64 x, y; - - Log(LOG_INFO, "sizeof(Int64) = %lu", sizeof(Int64)); - -#ifdef INT64_NATIVE - Log(LOG_INFO, "Using native 64-bit integers."); -#else - Log(LOG_INFO, "Using emulated 64-bit integers."); -#endif - - /* BSR Tests */ - - x = Int64Create(0x000000FF, 0x00000000); - - y = Int64Sra(x, 4); - AssertEquals("x >> 4", y, Int64Create(0x0000000F, 0xF0000000)); - - y = Int64Sra(x, 8); - AssertEquals("x >> 8", y, Int64Create(0x00000000, 0xFF000000)); - - y = Int64Sra(x, 36); - AssertEquals("x >> 36", y, Int64Create(0x00000000, 0x0000000F)); - - x = Int64Create(0xFF000000, 0x00000000); - - y = Int64Sra(x, 4); - AssertEquals("x >> 4", y, Int64Create(0xFFF00000, 0x00000000)); - - y = Int64Sra(x, 8); - AssertEquals("x >> 8", y, Int64Create(0xFFFF0000, 0x00000000)); - - y = Int64Sra(x, 63); - AssertEquals("x >> 63", y, Int64Create(0xFFFFFFFF, 0xFFFFFFFF)); - - /* BSL Tests */ - - x = Int64Create(0x00000000, 0xFF000000); - - y = Int64Sll(x, 4); - AssertEquals("x << 4", y, Int64Create(0x0000000F, 0xF0000000)); - - y = Int64Sll(x, 8); - AssertEquals("x << 8", y, Int64Create(0x000000FF, 0x00000000)); - - y = Int64Sll(x, 36); - AssertEquals("x << 36", y, Int64Create(0xF0000000, 0x00000000)); - - /* ADD Tests */ - - x = Int64Create(0x00000000, 0xF0000001); - y = Int64Create(0x00000000, 0x00000002); - AssertEquals("0xF0000001 + 0x00000002", Int64Add(x, y), Int64Create(0x00000000, 0xF0000003)); - - x = Int64Create(0x00000000, 0xF0000000); - y = Int64Create(0x00000000, 0x10000000); - AssertEquals("0xF0000000 + 0x10000000", Int64Add(x, y), Int64Create(0x00000001, 0x00000000)); - - x = Int64Create(0, 5); - y = Int64Neg(Int64Create(0, 10)); - AssertEquals("5 + (-10)", Int64Add(x, y), Int64Neg(Int64Create(0, 5))); - - /* SUB Tests */ - x = Int64Create(0x00000000, 0x00000005); - y = Int64Create(0x00000000, 0x00000002); - AssertEquals("0x00000005 - 0x00000002", Int64Sub(x, y), Int64Create(0x00000000, 0x00000003)); - - x = Int64Create(0x00000001, 0x00000000); - y = Int64Create(0x00000000, 0x00000001); - AssertEquals("0x00000001 0x00000000 - 0x00000001", Int64Sub(x, y), Int64Create(0x00000000, 0xFFFFFFFF)); - - x = Int64Create(0, 5); - y = Int64Create(0, 10); - AssertEquals("5 - 10", Int64Sub(x, y), Int64Neg(Int64Create(0, 5))); - - x = Int64Create(0, 5); - y = Int64Neg(Int64Create(0, 10)); - AssertEquals("5 - (-10)", Int64Sub(x, y), Int64Create(0, 15)); - - /* MUL Tests */ - x = Int64Create(0, 18); - y = Int64Create(0, 1); - AssertEquals("18 * 1", Int64Mul(x, y), Int64Create(0, 18)); - - x = Int64Create(0, 20); - y = Int64Create(0, 12); - AssertEquals("20 * 12", Int64Mul(x, y), Int64Create(0, 240)); - - x = Int64Create(0x00000000, 0x00000005); - y = Int64Create(0x00000000, 0x00000005); - AssertEquals("0x00000005 * 0x00000005", Int64Mul(x, y), Int64Create(0x00000000, 0x00000019)); - - x = Int64Create(0x00000001, 0x00000000); - y = Int64Create(0x00000000, 0x00000005); - AssertEquals("0x00000001 0x00000000 * 0x00000005", Int64Mul(x, y), Int64Create(0x00000005, 0x00000000)); - - /* DIV Tests */ - x = Int64Create(0, 12); - y = Int64Create(0, 4); - AssertEquals("12 / 4", Int64Div(x, y), Int64Create(0, 3)); - - /* MOD Tests */ - x = Int64Create(0x000000FF, 0x00000000); - y = Int64Create(0x00000000, 0x00000010); - AssertEquals("0x000000FF 0x00000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0)); - - x = Int64Create(0x00000000, 0xFF000000); - y = Int64Create(0x00000000, 0x00000010); - AssertEquals("0x00000000 0xFF000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0)); - - x = Int64Create(0xFF000000, 0x00000000); - y = Int64Create(0x00000000, 0x00000010); - AssertEquals("0xFF000000 0x00000000 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0)); - - x = Int64Create(0x00000000, 0x000000F0); - y = Int64Create(0x00000000, 0x00000010); - AssertEquals("0x00000000 0x000000F0 mod 0x00000010", Int64Rem(x, y), Int64Create(0, 0)); - - /* TODO: Add more tests for negative multiplication, division, and - * mod */ - - return 0; -} diff --git a/tools/uint64.c b/tools/uint64.c deleted file mode 100644 index 8e9f5f5..0000000 --- a/tools/uint64.c +++ /dev/null @@ -1,119 +0,0 @@ -#include - -#include - -/* AssertEquals(actual, expected) */ -int -AssertEquals(char *msg, UInt64 x, UInt64 y) -{ - if (!UInt64Eq(x, y)) - { - Log(LOG_ERR, "%s: Expected 0x%X 0x%X, got 0x%X 0x%X", msg, - UInt64High(y), UInt64Low(y), - UInt64High(x), UInt64Low(x)); - - return 0; - } - - return 1; -} - -int -Main(void) -{ - UInt64 x, y; - - Log(LOG_INFO, "sizeof(UInt64) = %lu", sizeof(UInt64)); - -#ifdef UINT64_NATIVE - Log(LOG_INFO, "Using native 64-bit integers."); -#else - Log(LOG_INFO, "Using emulated 64-bit integers."); -#endif - - /* BSR Tests */ - - x = UInt64Create(0x000000FF, 0x00000000); - - y = UInt64Srl(x, 4); - AssertEquals("x >> 4", y, UInt64Create(0x0000000F, 0xF0000000)); - - y = UInt64Srl(x, 8); - AssertEquals("x >> 8", y, UInt64Create(0x00000000, 0xFF000000)); - - y = UInt64Srl(x, 36); - AssertEquals("x >> 36", y, UInt64Create(0x00000000, 0x0000000F)); - - /* BSL Tests */ - - x = UInt64Create(0x00000000, 0xFF000000); - - y = UInt64Sll(x, 4); - AssertEquals("x << 4", y, UInt64Create(0x0000000F, 0xF0000000)); - - y = UInt64Sll(x, 8); - AssertEquals("x << 8", y, UInt64Create(0x000000FF, 0x00000000)); - - y = UInt64Sll(x, 36); - AssertEquals("x << 36", y, UInt64Create(0xF0000000, 0x00000000)); - - /* ADD Tests */ - - x = UInt64Create(0x00000000, 0xF0000001); - y = UInt64Create(0x00000000, 0x00000002); - AssertEquals("0xF0000001 + 0x00000002", UInt64Add(x, y), UInt64Create(0x00000000, 0xF0000003)); - - x = UInt64Create(0x00000000, 0xF0000000); - y = UInt64Create(0x00000000, 0x10000000); - AssertEquals("0xF0000000 + 0x10000000", UInt64Add(x, y), UInt64Create(0x00000001, 0x00000000)); - - /* SUB Tests */ - x = UInt64Create(0x00000000, 0x00000005); - y = UInt64Create(0x00000000, 0x00000002); - AssertEquals("0x00000005 - 0x00000002", UInt64Sub(x, y), UInt64Create(0x00000000, 0x00000003)); - - x = UInt64Create(0x00000001, 0x00000000); - y = UInt64Create(0x00000000, 0x00000001); - AssertEquals("0x00000001 0x00000000 - 0x00000001", UInt64Sub(x, y), UInt64Create(0x00000000, 0xFFFFFFFF)); - - /* MUL Tests */ - x = UInt64Create(0, 18); - y = UInt64Create(0, 1); - AssertEquals("18 * 1", UInt64Mul(x, y), UInt64Create(0, 18)); - - x = UInt64Create(0, 20); - y = UInt64Create(0, 12); - AssertEquals("20 * 12", UInt64Mul(x, y), UInt64Create(0, 240)); - - x = UInt64Create(0x00000000, 0x00000005); - y = UInt64Create(0x00000000, 0x00000005); - AssertEquals("0x00000005 * 0x00000005", UInt64Mul(x, y), UInt64Create(0x00000000, 0x00000019)); - - x = UInt64Create(0x00000001, 0x00000000); - y = UInt64Create(0x00000000, 0x00000005); - AssertEquals("0x00000001 0x00000000 * 0x00000005", UInt64Mul(x, y), UInt64Create(0x00000005, 0x00000000)); - - /* DIV Tests */ - x = UInt64Create(0, 12); - y = UInt64Create(0, 4); - AssertEquals("12 / 4", UInt64Div(x, y), UInt64Create(0, 3)); - - /* MOD Tests */ - x = UInt64Create(0x000000FF, 0x00000000); - y = UInt64Create(0x00000000, 0x00000010); - AssertEquals("0x000000FF 0x00000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0)); - - x = UInt64Create(0x00000000, 0xFF000000); - y = UInt64Create(0x00000000, 0x00000010); - AssertEquals("0x00000000 0xFF000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0)); - - x = UInt64Create(0xFF000000, 0x00000000); - y = UInt64Create(0x00000000, 0x00000010); - AssertEquals("0xFF000000 0x00000000 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0)); - - x = UInt64Create(0x00000000, 0x000000F0); - y = UInt64Create(0x00000000, 0x00000010); - AssertEquals("0x00000000 0x000000F0 mod 0x00000010", UInt64Rem(x, y), UInt64Create(0, 0)); - - return 0; -} From 03fe5ca355e63201924d841cb9c852be4eadf9d2 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 08:33:37 -0400 Subject: [PATCH 10/37] Move http man page to Cytoplasm from Telodendria. --- man/man1/http.1 | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 man/man1/http.1 diff --git a/man/man1/http.1 b/man/man1/http.1 new file mode 100644 index 0000000..3a108e9 --- /dev/null +++ b/man/man1/http.1 @@ -0,0 +1,70 @@ +.Dd $Mdocdate: March 12 2023 $ +.Dt HTTP 1 +.Os Telodendria Project +.Sh NAME +.Nm http +.Nd A simple command line utility for making HTTP requests. +.Sh SYNOPSIS +.Nm +.Op Fl i +.Op Fl X Ar method +.Op Fl H Ar header +.Op Fl d Ar data +.Op URL +.Sh DESCRIPTION +.Nm +Is a command line HTTP client. It is very heavily inspired by +.Xr curl 1 , +and even uses the same flag names when possible. However, +.Nm +is designed to be much simpler than +.Xr curl 1 , +and is built on Telodendria's own +.Xr HttpClient 3 +API. It primarily exists to test +.Xr HttpClient 3 +and +.Xr HttpServer 3 , +and make development of Telodendria possible without having +to install any external tools. +.sp +The options are as follows: +.Bl -tag -width Ds +.It Fl i +Display the response headers before writing the body. +.It Fl X Ar method +Set the request method. This can be any of the options +allowed by the +.Xr Http 3 +API; unlike +.Xr curl 1 , +it cannot be any arbitrary string. +.It Fl H Ar header +Set a request header, in the form of ``Header: value''. This option +can be set multiple times to add multiple request headers. +.It Fl d Ar data +Send data to the server in the request body. If +.Ar data +starts with ``@'', then the file specified after is opened +and read in. If it is ``@-'', then standard input is used. +Otherwise, the string is passed to the server as-is. +.El +.Pp +.Nm +also requires a +.Ar URL +to make the request to. The URL is parsed by the +.Xr Uri 3 +API, so consult that page for the syntax of URLs. +.Sh EXIT STATUS +.Nm +exits with +.Va EXIT_SUCCESS +if all command line options were valid, the request was +made successfully, and the server returns an HTTP code +that indicates success. It exits with +.Va EXIT_FAILURE +in all other scenarios. +.Sh SEE ALSO +.Xr HttpClient 3 , +.Xr Uri 3 From 6ab1c7919b1b16090e88c01d7ab3563abc76abe8 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 11:25:32 -0400 Subject: [PATCH 11/37] Explicitly set the `make` compiler to `cc`. This makes it work out of the box on GNU systems where GNU make defaults to c99, which doesn't accept -std=c89. --- configure | 1 + 1 file changed, 1 insertion(+) diff --git a/configure b/configure index bdb915b..e217c47 100755 --- a/configure +++ b/configure @@ -195,6 +195,7 @@ cat << EOF > Makefile # Generated by '$0' on $(date). # This file should generally not be manually edited. +CC = cc PREFIX = ${PREFIX} CFLAGS = ${CFLAGS} LDFLAGS = ${LDFLAGS} From 8ffade37b19e9d5b5019b517f33c47faf0392b15 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 11:26:27 -0400 Subject: [PATCH 12/37] Add a meta header. This allows programs to print the name and version of the library that is currently in use. --- src/Cytoplasm.c | 35 ++++++++++++++++++++++++ src/include/Cytoplasm.h | 60 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 src/Cytoplasm.c create mode 100644 src/include/Cytoplasm.h diff --git a/src/Cytoplasm.c b/src/Cytoplasm.c new file mode 100644 index 0000000..43ff294 --- /dev/null +++ b/src/Cytoplasm.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * + * 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 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 + +char *CytoplasmGetName() +{ + return LIB_NAME; +} + +char *CytoplasmGetVersion() +{ + return LIB_VERSION; +} \ No newline at end of file diff --git a/src/include/Cytoplasm.h b/src/include/Cytoplasm.h new file mode 100644 index 0000000..f965f2f --- /dev/null +++ b/src/include/Cytoplasm.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * + * 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 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 CYTOPLASM_CYTOPLASM_H +#define CYTOPLASM_CYTOPLASM_H + +/*** + * @Nm Cytoplasm + * @Nd A simple API that provides metadata on the library itself. + * @Dd September 30 2022 + * @Xr Sha2 + * + * This API simply provides name and versioning information for the + * currently loaded library. + */ + + +/** + * Get the name that this library was compiled with. In most cases, + * this will be hard-coded to "Cytoplasm", but it may differ if, for + * some reason, there exists another ABI-compatible library that + * wishes to report its name. + * + * This function really only exists because the information is + * available along side of the version information so for + * consistency, it made sense to include both. + */ +extern char * CytoplasmGetName(void); + +/** + * Get the library version. This will be useful mostly for printing + * to log files, but it may also be used by a program to verify that + * the version is new enough. + * + * This function returns a string, which should usually be able to be + * parsed using sscanf() if absolutely necessary. + */ +extern char * CytoplasmGetVersion(void); + +#endif /* CYTOPLASM_CYTOPLASM_H */ \ No newline at end of file From dadc1ac5c7664b9d0b8a1b474968ebb01f4867b2 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 11:26:48 -0400 Subject: [PATCH 13/37] Provide build instructions and logo. Closes #8. --- README.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 58 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 416e962..d173524 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Cytoplasm (libcytoplasm) +

+

Cytoplasm (libcytoplasm)

Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications. It allows applications to take advantage of the speed, flexibility, and simplicity of the C programming language, while providing helpful code to allow applications to perform various complex tasks with minimal effort. Cytoplasm provides high-level data structures, a basic logging facility, an HTTP client and server, and more. It also reports memory leaks, which can aid in debugging. @@ -14,16 +15,27 @@ The name "Cytoplasm" was chosen for a few reasons. It plays off the precedent se Cytoplasm also starts with a C, which I think is a nice touch for C libraries. It's also fun to say and unique enough that searching for "libcytoplasm" should bring you to this project and not some other one. -## Building +## Requirements -If your operating system or software distribution provides a pre-built package of Cytoplasm, you should prefer to use that instead of building it from source. +Cytoplasm makes the following assumptions about the underlying hardware: -Cytoplasm aims to have zero dependencies beyond what is mandated by POSIX. You only need the standard math and pthread libraries to build it. TLS support can optionally be enabled with the configuration script. The supported TLS implementations are as follows: +- It has words sizes that are powers of 2, and a native 32-bit integer type exists. +- Integers are represented using two's compliment for negatives. + +The ANSI C standard requires an integer type of at least 32 bits, but does not require any more. If Cytoplasm is built on 32-bit platforms that don't provide a native 64-bit integer type, Cytoplasm emulates 64-bit integers. This can make it more portable. + +Cytoplasm aims to have zero software dependencies beyond what is mandated by POSIX. You only need the standard math and pthread libraries to build it. TLS support can optionally be enabled with the configuration script. The supported TLS implementations are as follows: - OpenSSL - LibreSSL -If TLS support is not enabled, all APIs that use it should fall back to non-TLS behavior in a sensible manner. For example, if TLS support is not enabled, then the HTTP client API will simply return an error if a TLS connection is requested. Cytoplasm uses the standard C library build procedure. Just run these commands: +If TLS support is not enabled, all APIs that use it should fall back to non-TLS behavior in a sensible manner. For example, if TLS support is not enabled, then the HTTP client API will simply return an error if a TLS connection is requested. + +## Building + +If your operating system or software distribution provides a pre-built package of Cytoplasm, you should prefer to use that instead of building it from source. + +Cytoplasm uses the standard C library build procedure. Just run these commands: ``` ./configure @@ -43,6 +55,40 @@ This will produce the following out/ directory: You can also run `make install` as `root` to install Cytoplasm to the system. This will install the libraries, tools, and `man` pages. +The `configure` script has a number of optional flags, which are as follows: + +- `--with-(openssl|libressl)`: Select the TLS implementation to use. OpenSSL is selected by default. +- `--disable-tls`: Disable TLS altogether. +- `--prefix=`: Set the install prefix to set by default in the `Makefile`. This defaults to `/usr/local`, which should be appropriate for most Unix-like systems. +- `--(enable|disable)-ld-extra`: Control whether or not to enable additional linking flags that create a more optimized binary. For large compilers such as GCC and Clang, these flags should be enabled. However, if you are using a small or more obscure compiler, then these flags may not be supported, so you can disable them with this option. +- `--(enable|disable)-debug`: Control whether or not to enable debug mode. This sets the optimization level to 0 and builds with debug symbols. Useful for running with a debugger. +- `--static` and `--no-static`: Controls whether static binaries for tools are built by default. On BSD systems, `--static` is perfectly acceptable, but on GNU systems, `--no-static` is often desirable to silence warnings about static binaries emitted by the GNU linker. + +Cytoplasm can be customized with the following options: + +- `--lib-name=`: The output name of the library. This defaults to `Cytoplasm` and should in most cases not be changed. +- `--lib-version=`: The version string to embed in the library binaries. This can be used to indicate build customizations or non-release versions of Cytoplasm. + +The following recipes are available in the generated `Makefile`: + +- `all`: This is the default target. It builds everything. +- `Cytoplasm`: Build the `libCytoplasm.(so|a)` binaries. If you specified an alternative `--lib-name`, then this target will be named after that. +- `docs`: Generate the header documentation as `man` pages. +- `tools`: Build the supplemental tools which may be useful for development. +- `clean`: Remove the build and output directories. Cytoplasm builds are out-of-tree, which greatly simplifies this recipe compared to in-tree builds. + +If you're developing Cytoplasm, these recipes may also be helpful: + +- `format`: Format the source code using `indent`. This may require a BSD `indent` because last time I tried GNU `indent`, it didn't like the flags in `indent.pro`. Your mileage may vary. +- `license`: Update the license headers in all source code files with the contents of the `LICENSE.txt`. + +To install Telodendria to your system, the following recipes are available: + +- `install`: This installs Cytoplasm under the prefix set with `./configure --prefix=` or with `make PREFIX=`. By default, the `make` `PREFIX` is set to whatever was set with `configure --prefix`. +- `uninstall`: Uninstall Cytoplasm from the same prefix as specified above. + +After a build, you can find the object files in `build/` and the output binaries in `out/lib/`. + ## Usage Cytoplasm provides the typical .so and .a files, which can be used to link programs with it in the usual way. Somewhat *unusually* for C libraries, however, it provides its own `main()` function, so programs written with Cytoplasm provide `Main()` instead, which is called by Cytoplasm. Cytoplasm works this way because it needs to perform some setup logic before user code runs and some teardown logic after user code returns. @@ -63,7 +109,7 @@ If this file is `Hello.c`, then you can compile it by doing this: $ cc -o hello Hello.c -lCytoplasm -The full form of Main() expected by the stub is as follows: +The full form of `Main()` expected by the stub is as follows: ```c int Main(Array *args, HashMap *env); @@ -72,3 +118,9 @@ The full form of Main() expected by the stub is as follows: The first argument is a Cytoplasm array of the command line arguments, and the second is a Cytoplasm hash map of environment variables. Most linkers will let programs omit the `env` argument, or both arguments if you don't need either. The return value of `Main()` is returned to the operating system, as would be expected. Note that both arguments to Main may be treated like any other Cytoplasm array or hash map. However, do not invoke `ArrayFree()` or `HashMapFree()` on the passed pointers, because memory is cleaned up after `Main()` returns. + +## License + +All of the code and documentation for Cytoplasm is licensed under the same license as Telodendria itself. Please refer to [Telodendria → License](/Telodendria/Telodendria#license) for details. + +The Cytoplasm logo was designed by [Tobskep](https://tobskep.com) and is licensed under the [Creative Commons Attribution-ShareAlike 4.0](https://creativecommons.org/licenses/by-sa/4.0/) license. \ No newline at end of file From 4e73273cbd61daabecf12e690f6d58a755279970 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Wed, 1 Nov 2023 12:20:52 -0400 Subject: [PATCH 14/37] Add CHANGELOG.md --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9ec2695 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,18 @@ +# Cytoplasm Change Log + +This document contains the complete change log for every official release of +Cytoplasm. It is intended to be updated with every commit that makes a user-facing +change worth reporting in the change log. As such, it changes frequently between +releases. Final change log entries are published as [Releases](releases). + +## v0.4.0 + +**Released on November 1, 2023** + +This is the first independent release of Cytoplasm! Last month, Cytoplasm was +split off of [Telodendria](/Telodendria/Telodendria) to become its own independent +project with its own independent releases. This allows it to develop at a much more +rapid pace than Telodendria. + +Changes in future releases will be reported here. Since this is the first release, +there are no changes to show. \ No newline at end of file From d242597e731be1bebeff9530c6a653443a6add16 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 4 Nov 2023 15:58:23 -0400 Subject: [PATCH 15/37] Allow customization of compiler used in configure. --- configure | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/configure b/configure index e217c47..c9e6a81 100755 --- a/configure +++ b/configure @@ -18,7 +18,7 @@ LIBS="-lm -pthread" # Set default args for all platforms -SCRIPT_ARGS="--prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@" +SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@" # Set platform specific args case "$(uname)" in @@ -36,6 +36,9 @@ echo "Ran with arguments: $SCRIPT_ARGS" # Process all arguments for arg in $SCRIPT_ARGS; do case "$arg" in + --cc=*) + CC=$(echo "$arg" | cut -d '=' -f 2-) + ;; --with-openssl) TLS_IMPL="TLS_OPENSSL" TLS_LIBS="-lcrypto -lssl" @@ -81,7 +84,7 @@ for arg in $SCRIPT_ARGS; do STATIC="" ;; *) - echo "Invalid argument: $1" + echo "Invalid argument: $arg" exit 1 ;; esac @@ -129,7 +132,7 @@ compile_obj() { src="$1" obj="$2" - cc -I${INCLUDE} -MM -MT "${obj}" "${src}" + ${CC} -I${INCLUDE} -MM -MT "${obj}" "${src}" echo "${TAB}@mkdir -p $(dirname ${obj})" echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\"" } @@ -195,7 +198,7 @@ cat << EOF > Makefile # Generated by '$0' on $(date). # This file should generally not be manually edited. -CC = cc +CC = ${CC} PREFIX = ${PREFIX} CFLAGS = ${CFLAGS} LDFLAGS = ${LDFLAGS} From 618bcbbac335e2809b82baf548a33d4643308391 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 6 Nov 2023 14:19:49 -0500 Subject: [PATCH 16/37] `j2s`: Add 'extern' type and ignored fields. Closes #14. --- CHANGELOG.md | 10 ++++++++ tools/j2s.c | 71 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ec2695..d73ef72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ Cytoplasm. It is intended to be updated with every commit that makes a user-faci change worth reporting in the change log. As such, it changes frequently between releases. Final change log entries are published as [Releases](releases). +## v0.4.1 + +### Tools + +#### `j2s` + +- Added an option to allow additional fields in structures and ignore them in +encoding and decoding. Note that additional fields are totally untouched—they +are not even initialized to a default value. + ## v0.4.0 **Released on November 1, 2023** diff --git a/tools/j2s.c b/tools/j2s.c index 9a85a00..674d6d3 100644 --- a/tools/j2s.c +++ b/tools/j2s.c @@ -309,22 +309,23 @@ Main(Array * args) ArrayAdd(requiredTypes, StrDuplicate(type)); } - typeFieldsVal = HashMapGet(typeObj, "fields"); - if (JsonValueType(typeFieldsVal) != JSON_OBJECT) - { - Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type); - goto finish; - } - - typeFields = JsonValueAsObject(typeFieldsVal); - if (StrEquals(typeType, "struct")) { + typeFieldsVal = HashMapGet(typeObj, "fields"); + if (JsonValueType(typeFieldsVal) != JSON_OBJECT) + { + Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type); + goto finish; + } + + typeFields = JsonValueAsObject(typeFieldsVal); + while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal)) { char *fieldType; int isArrType = 0; JsonValue *requiredVal; + JsonValue *ignoreVal; if (JsonValueType(fieldVal) != JSON_OBJECT) { @@ -379,10 +380,26 @@ Main(Array * args) Log(LOG_ERR, "Validation error: 'types.%s.fields.%s.required' must be a boolean.", type, fieldName); goto finish; } + + ignoreVal = HashMapGet(fieldObj, "ignore"); + if (ignoreVal && JsonValueType(ignoreVal) != JSON_BOOLEAN) + { + Log(LOG_ERR, "Validation error: 'types.%s.fields.%s.ignore' must be a boolean.", type, fieldName); + goto finish; + } } } else if (StrEquals(typeType, "enum")) { + typeFieldsVal = HashMapGet(typeObj, "fields"); + if (JsonValueType(typeFieldsVal) != JSON_OBJECT) + { + Log(LOG_ERR, "Validation error: 'types.%s.fields' must be an object.", type); + goto finish; + } + + typeFields = JsonValueAsObject(typeFieldsVal); + while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal)) { char *name; @@ -403,16 +420,17 @@ Main(Array * args) } } } + else if (StrEquals(typeType, "extern")) + { + /* + * No code will be generated for this type. We simply assume that it exists. + */ + } else { Log(LOG_ERR, "Validation error: 'types.%s.type' must be 'struct' or 'enum'.", type); goto finish; } - /* - * TODO: Add "extern" type that doesn't actually generate any code, - * but trusts the user that it has been generated somewhere else. This - * is effectively "importing" types. - */ } sortedNodes = GraphTopologicalSort(dependencyGraph, &sortedNodesLen); @@ -471,6 +489,12 @@ Main(Array * args) } typeType = JsonValueAsString(JsonGet(types, 2, type, "type")); + + if (StrEquals(typeType, "extern")) + { + continue; + } + fields = JsonValueAsObject(JsonGet(types, 2, type, "fields")); StreamPrintf(headerFile, "typedef %s %s\n{\n", typeType, type); @@ -615,11 +639,18 @@ Main(Array * args) { char *key = ArrayGet(keys, i); int required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required")); + int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType); char *jsonTypeStr = JsonTypeToStr(jsonType); + if (ignore) + { + StreamPrintf(implFile, " /* Ignored field: %s */\n\n", key); + continue; + } + StreamPrintf(implFile, " val = HashMapGet(json, \"%s\");\n", Trim('_', key)); StreamPrintf(implFile, " if (val)\n {\n"); @@ -847,6 +878,13 @@ Main(Array * args) char *key = ArrayGet(keys, i); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); + int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); + + if (ignore) + { + StreamPrintf(implFile, " /* Ignored field: %s */\n\n", key); + continue; + } if (StrEquals(fieldType, "array")) { @@ -1022,8 +1060,9 @@ Main(Array * args) else { /* Ignore primitives but call the appropriate free - * method on declared types */ - if (!isEnum && HashMapGet(types, fieldType)) + * method on declared types that aren't "extern". */ + char *fieldTypeType = JsonValueAsString(JsonGet(types, 2, fieldType, "type")); + if (!isEnum && HashMapGet(types, fieldType) && !StrEquals(fieldTypeType, "extern")) { StreamPrintf(implFile, " %sFree(&val->%s);\n", fieldType, key); } From 01da37f7d757e4016a17c86beff4b890922a9074 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 6 Nov 2023 14:20:42 -0500 Subject: [PATCH 17/37] Bump version number. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index c9e6a81..f8b0554 100755 --- a/configure +++ b/configure @@ -18,7 +18,7 @@ LIBS="-lm -pthread" # Set default args for all platforms -SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.0 --static $@" +SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.1 --static $@" # Set platform specific args case "$(uname)" in From ba1ac5b42b219d7a89790f9da019376938832ef3 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 6 Nov 2023 19:59:46 -0500 Subject: [PATCH 18/37] Add `JsonMerge()`. Closes #15. --- src/Json.c | 29 +++++++++++++++++++++++++++++ src/include/Json.h | 9 +++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Json.c b/src/Json.c index 6922e14..10a0316 100644 --- a/src/Json.c +++ b/src/Json.c @@ -1433,3 +1433,32 @@ finish: va_end(argp); return val; } + +void +JsonMerge(HashMap *obj1, HashMap *obj2) +{ + char *key; + JsonValue *val2; + + while (HashMapIterate(obj2, &key, (void **) &val2)) + { + JsonValue *val1 = HashMapGet(obj1, key); + + if (val1) + { + if (JsonValueType(val1) == JsonValueType(val2) && + JsonValueType(val1) == JSON_OBJECT) + { + JsonMerge(JsonValueAsObject(val1), JsonValueAsObject(val2)); + } + else + { + JsonValueFree(HashMapSet(obj1, key, JsonValueDuplicate(val2))); + } + } + else + { + HashMapSet(obj1, key, JsonValueDuplicate(val2)); + } + } +} diff --git a/src/include/Json.h b/src/include/Json.h index cc4a63d..5a14aab 100644 --- a/src/include/Json.h +++ b/src/include/Json.h @@ -320,4 +320,13 @@ extern JsonValue * JsonGet(HashMap *, size_t,...); */ extern JsonValue * JsonSet(HashMap *, JsonValue *, size_t,...); +/** + * Recursively merge two JSON objects. The second object is merged + * on top of the first; any keys present in the first object that are + * also present in the second object are replaced with those in the + * second object, and any keys present in the second object that are + * not present in the first object are copied to the first object. + */ +extern void JsonMerge(HashMap *, HashMap *); + #endif /* CYTOPLASM_JSON_H */ From bc6739303690d32563d47486e66c03eef503fce5 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 6 Nov 2023 21:28:10 -0500 Subject: [PATCH 19/37] Update CHANGELOG.md --- CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d73ef72..0b7881f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,12 @@ releases. Final change log entries are published as [Releases](releases). ## v0.4.1 -### Tools +### New Features -#### `j2s` - -- Added an option to allow additional fields in structures and ignore them in +- Added an option to `j2s` to allow additional fields in structures and ignore them in encoding and decoding. Note that additional fields are totally untouched—they are not even initialized to a default value. +- Added `JsonMerge()` to the JSON API to merge two JSON objects together. ## v0.4.0 From 29070c8f41c354e032e763a2eb01079ce221fb69 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Mon, 20 Nov 2023 09:51:08 -0500 Subject: [PATCH 20/37] Fix memory leak in code generated by `j2s` code. Closes #17. --- CHANGELOG.md | 2 ++ tools/j2s.c | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b7881f..3bfd31c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ releases. Final change log entries are published as [Releases](releases). - Added an option to `j2s` to allow additional fields in structures and ignore them in encoding and decoding. Note that additional fields are totally untouched—they are not even initialized to a default value. +- Fixed a memory leak that would occur in code generated by `j2s` under + specific circumstances. - Added `JsonMerge()` to the JSON API to merge two JSON objects together. ## v0.4.0 diff --git a/tools/j2s.c b/tools/j2s.c index 674d6d3..57a8b6e 100644 --- a/tools/j2s.c +++ b/tools/j2s.c @@ -660,11 +660,15 @@ Main(Array * args) StreamPrintf(implFile, " }\n\n"); if (StrEquals(fieldType, "array")) { - StreamPrintf(implFile, " out->%s = JsonValueAsArray(JsonValueDuplicate(val));\n", key); + StreamPrintf(implFile, " val = JsonValueDuplicate(val);\n"); + StreamPrintf(implFile, " out->%s = JsonValueAsArray(val);\n", key); + StreamPrintf(implFile, " Free(val); /* Not JsonValueFree() because we want the inner value. */\n"); } else if (StrEquals(fieldType, "object")) { - StreamPrintf(implFile, " out->%s = JsonValueAsObject(JsonValueDuplicate(val));\n", key); + StreamPrintf(implFile, " val = JsonValueDuplicate(val);\n"); + StreamPrintf(implFile, " out->%s = JsonValueAsObject(val);\n", key); + StreamPrintf(implFile, " Free(val); /* Not JsonValueFree() because we want the inner value. */\n"); } else if (*fieldType == '[' && fieldType[strlen(fieldType) - 1] == ']') { From 17f1a41519074f63b3cbd55851db4e8cc5be5e0a Mon Sep 17 00:00:00 2001 From: lda Date: Sat, 2 Dec 2023 10:25:28 -0500 Subject: [PATCH 21/37] `HttpRouter`: Decode path parts before matching. (#19) Required by Telodendria/Telodendria#44. Reviewed-on: https://git.telodendria.io/Telodendria/Cytoplasm/pulls/19 Co-authored-by: lda Co-committed-by: lda --- src/HttpRouter.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/HttpRouter.c b/src/HttpRouter.c index 981a0f8..ef16399 100644 --- a/src/HttpRouter.c +++ b/src/HttpRouter.c @@ -23,6 +23,7 @@ */ #include +#include #include #include #include @@ -228,12 +229,15 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) regmatch_t pmatch[REG_MAX_SUB]; + pathPart = HttpUrlDecode(pathPart); + i = 0; while (HashMapIterateReentrant(node->children, &key, (void **) &val, &i)) { if (regexec(&val->regex, pathPart, REG_MAX_SUB, pmatch, 0) == 0) { + Free(pathPart); break; } @@ -243,6 +247,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) if (!val) { exec = NULL; + Free(pathPart); break; } @@ -263,12 +268,14 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) substr = StrSubstr(pathPart, cpmatch.rm_so, cpmatch.rm_eo); if (pmatch[i].rm_so == -1) { + Free(pathPart); break; } ArrayAdd(matches, substr); } } + Free(pathPart); } Free(path); } From 928e9c822378d86790659659af9589d75dbe05f7 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 2 Dec 2023 10:26:24 -0500 Subject: [PATCH 22/37] Update CHANGELOG.md --- CHANGELOG.md | 57 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bfd31c..71cfee1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,29 +1,30 @@ -# Cytoplasm Change Log - -This document contains the complete change log for every official release of -Cytoplasm. It is intended to be updated with every commit that makes a user-facing -change worth reporting in the change log. As such, it changes frequently between -releases. Final change log entries are published as [Releases](releases). - -## v0.4.1 - -### New Features - -- Added an option to `j2s` to allow additional fields in structures and ignore them in -encoding and decoding. Note that additional fields are totally untouched—they -are not even initialized to a default value. -- Fixed a memory leak that would occur in code generated by `j2s` under - specific circumstances. -- Added `JsonMerge()` to the JSON API to merge two JSON objects together. - -## v0.4.0 - -**Released on November 1, 2023** - -This is the first independent release of Cytoplasm! Last month, Cytoplasm was -split off of [Telodendria](/Telodendria/Telodendria) to become its own independent -project with its own independent releases. This allows it to develop at a much more -rapid pace than Telodendria. - -Changes in future releases will be reported here. Since this is the first release, +# Cytoplasm Change Log + +This document contains the complete change log for every official release of +Cytoplasm. It is intended to be updated with every commit that makes a user-facing +change worth reporting in the change log. As such, it changes frequently between +releases. Final change log entries are published as [Releases](releases). + +## v0.4.1 + +### New Features + +- Added an option to `j2s` to allow additional fields in structures and ignore them in +encoding and decoding. Note that additional fields are totally untouched—they +are not even initialized to a default value. +- Fixed a memory leak that would occur in code generated by `j2s` under + specific circumstances. +- Added `JsonMerge()` to the JSON API to merge two JSON objects together. +- Make `HttpRouter` decode path parts before matching them on regular expressions. + +## v0.4.0 + +**Released on November 1, 2023** + +This is the first independent release of Cytoplasm! Last month, Cytoplasm was +split off of [Telodendria](/Telodendria/Telodendria) to become its own independent +project with its own independent releases. This allows it to develop at a much more +rapid pace than Telodendria. + +Changes in future releases will be reported here. Since this is the first release, there are no changes to show. \ No newline at end of file From 3788d044e66c87492e0eec178011e92ccee20abc Mon Sep 17 00:00:00 2001 From: lda Date: Thu, 14 Dec 2023 18:31:20 +0100 Subject: [PATCH 23/37] [FIX] Fix potential double-free issue in Cytoplasm --- src/HttpRouter.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HttpRouter.c b/src/HttpRouter.c index ef16399..f548b9b 100644 --- a/src/HttpRouter.c +++ b/src/HttpRouter.c @@ -237,7 +237,6 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) { if (regexec(&val->regex, pathPart, REG_MAX_SUB, pmatch, 0) == 0) { - Free(pathPart); break; } From 44b7f45bb736c7fdcc5fc8bb7a703726e0552546 Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 1 Jan 2024 07:57:11 -0500 Subject: [PATCH 24/37] [FIX] Fix other potential double-free MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Was done "à la va-vite" since I can't really work on it directly right now. --- src/HttpRouter.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/HttpRouter.c b/src/HttpRouter.c index f548b9b..02e6213 100644 --- a/src/HttpRouter.c +++ b/src/HttpRouter.c @@ -267,7 +267,6 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) substr = StrSubstr(pathPart, cpmatch.rm_so, cpmatch.rm_eo); if (pmatch[i].rm_so == -1) { - Free(pathPart); break; } From d0969d0dd7466eda19af6da67f37cc4502645076 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 11:08:44 -0500 Subject: [PATCH 25/37] Add a simple CI workflow for compiling Cytoplasm. (#27) This will allow us to pick up compiler warnings from other systems, mainly 32-bit ones. 32-bit systems have different integer sizes that cause all kinds of warnings that we should really address. Reviewed-on: https://git.telodendria.io/Telodendria/Cytoplasm/pulls/27 --- .gitea/workflows/compile.yaml | 25 +++++++++++++++++++++++++ configure | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/compile.yaml diff --git a/.gitea/workflows/compile.yaml b/.gitea/workflows/compile.yaml new file mode 100644 index 0000000..1185758 --- /dev/null +++ b/.gitea/workflows/compile.yaml @@ -0,0 +1,25 @@ +name: Compile Cytoplasm +run-name: Compile Cytoplasm on ${{ gitea.actor }} +on: [push] + +jobs: + "Compile Cytoplasm": + strategy: + matrix: + os: [debian-v12.4, alpine-v3.19, openbsd-v7.4, freebsd-v14.0, netbsd-v9.3] + arch: [x86, x86_64] + exclude: + # 32-bit OpenBSD does not behave well in QEMU. Even when using + # QEMU to emulate i386, it utilizes 100% of its CPU core and is + # still extremely sluggish. Thus, we don't have a working 32-bit + # OpenBSD runner, so exclude it from the matrix configuration. + - os: openbsd-v7.4 + arch: x86 + runs-on: ["${{ matrix.os }}", "${{ matrix.arch }}"] + steps: + - name: Check out repository + uses: actions/checkout@v3 + - name: Configure Cytoplasm + run: ./configure + - name: Build Cytoplasm + run: make diff --git a/configure b/configure index f8b0554..a9f682b 100755 --- a/configure +++ b/configure @@ -18,7 +18,7 @@ LIBS="-lm -pthread" # Set default args for all platforms -SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.1 --static $@" +SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.1 $@" # Set platform specific args case "$(uname)" in From 662696ce12640ebfa4540d3820244c6e7cc16179 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 17:13:45 -0500 Subject: [PATCH 26/37] C99 Compliance (#29) This pull request brings Cytoplasm up from C89 to C99, which makes it much more portable across platforms. In particular, this pull request solves a number of issues with 32-bit platforms. Closes #28. Closes #12. Closes #20. Reviewed-on: https://git.telodendria.io/Telodendria/Cytoplasm/pulls/29 --- configure | 94 +++++---- src/Array.c | 20 +- src/Base64.c | 8 +- src/Cron.c | 55 +++--- src/Cytoplasm.c | 20 +- src/Db.c | 51 +++-- src/HashMap.c | 14 +- src/HttpClient.c | 3 +- src/HttpRouter.c | 22 +-- src/HttpServer.c | 30 +-- src/Int64.c | 399 --------------------------------------- src/Json.c | 59 +++--- src/Memory.c | 8 +- src/Queue.c | 18 +- src/Rand.c | 34 ++-- src/Runtime.c | 8 +- src/Sha/Sha1.c | 43 +++-- src/Sha/Sha256.c | 31 ++- src/Str.c | 23 ++- src/Stream.c | 11 +- src/UInt64.c | 265 -------------------------- src/Util.c | 81 +++----- src/include/Array.h | 9 +- src/include/Base64.h | 3 +- src/include/Cron.h | 8 +- src/include/Cytoplasm.h | 29 +-- src/include/Db.h | 9 +- src/include/HashMap.h | 4 +- src/include/HttpRouter.h | 4 +- src/include/HttpServer.h | 3 +- src/include/Int.h | 122 ------------ src/include/Int64.h | 252 ------------------------- src/include/Json.h | 16 +- src/include/Memory.h | 1 + src/include/Queue.h | 7 +- src/include/Rand.h | 8 +- src/include/Str.h | 12 +- src/include/Stream.h | 6 +- src/include/UInt64.h | 252 ------------------------- src/include/Util.h | 9 +- 40 files changed, 384 insertions(+), 1667 deletions(-) delete mode 100644 src/Int64.c delete mode 100644 src/UInt64.c delete mode 100644 src/include/Int.h delete mode 100644 src/include/Int64.h delete mode 100644 src/include/UInt64.h diff --git a/configure b/configure index a9f682b..f962059 100755 --- a/configure +++ b/configure @@ -13,23 +13,44 @@ SRC="src" INCLUDE="src/include" TOOLS="tools" -CFLAGS="-Wall -Wextra -pedantic -std=c89 -O3 -pipe -D_DEFAULT_SOURCE -I${INCLUDE}" -LIBS="-lm -pthread" +# Default compiler flags. These must be supported by all POSIX C compilers. +# "Fancy" compilers that have additional options must be detected and set below. +CFLAGS="-O1 -D_DEFAULT_SOURCE -I${INCLUDE}" +LIBS="-lm -lpthread" +# Default args for all platforms. +SCRIPT_ARGS="--prefix=/usr/local --lib-name=Cytoplasm" -# Set default args for all platforms -SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.1 $@" - -# Set platform specific args +# Set SSL flags depending on the platform. case "$(uname)" in OpenBSD) - SCRIPT_ARGS="--with-libressl $SCRIPT_ARGS" + SCRIPT_ARGS="${SCRIPT_ARGS} --with-libressl" ;; *) - SCRIPT_ARGS="--with-openssl $SCRIPT_ARGS" + SCRIPT_ARGS="${SCRIPT_ARGS} --with-openssl" ;; esac +# Set compiler depending on the platform. +case "$(uname)" in + Linux|NetBSD) + # These systems typically use GCC. + SCRIPT_ARGS="${SCRIPT_ARGS} --cc=gcc" + ;; + OpenBSD|FreeBSD) + # These systems typically use Clang. + SCRIPT_ARGS="${SCRIPT_ARGS} --cc=clang" + ;; + *) + # Use default compiler which is required to be present on + # all POSIX-compliant systems. + SCRIPT_ARGS="${SCRIPT_ARGS} --cc=c99" + ;; +esac + +# Append any additional args specified by user +SCRIPT_ARGS="${SCRIPT_ARGS} $@" + echo "Processing options..." echo "Ran with arguments: $SCRIPT_ARGS" @@ -38,6 +59,14 @@ for arg in $SCRIPT_ARGS; do case "$arg" in --cc=*) CC=$(echo "$arg" | cut -d '=' -f 2-) + case "${CC}" in + gcc*|clang*) + # "Fancy" compilers that support a plethora of additional flags we + # want to enable if present. + CFLAGS="-Wall -Werror -pedantic -std=c99 ${CFLAGS}" + LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections" + ;; + esac ;; --with-openssl) TLS_IMPL="TLS_OPENSSL" @@ -54,35 +83,15 @@ for arg in $SCRIPT_ARGS; do --prefix=*) PREFIX=$(echo "$arg" | cut -d '=' -f 2-) ;; - --enable-ld-extra) - LD_EXTRA="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections" - ;; - --disable-ld-extra) - LD_EXTRA="" - ;; --lib-name=*) LIB_NAME=$(echo "$arg" | cut -d '=' -f 2-) ;; - --lib-version=*) - LIB_VERSION=$(echo "$arg" | cut -d '=' -f 2-) - ;; --enable-debug) DEBUG="-O0 -g" - echo "Notice: --enable-debug implies --disable-ld-extra and --no-static." - echo "You must explicitly provide --enable-ld-extra and/or --static after" - echo "specifying --enable-debug if you wish to enable these features in debug mode." - LD_EXTRA="" - STATIC="" ;; --disable-debug) DEBUG="" ;; - --static) - STATIC="-static -Wl,-static" - ;; - --no-static) - STATIC="" - ;; *) echo "Invalid argument: $arg" exit 1 @@ -95,8 +104,8 @@ if [ -n "$TLS_IMPL" ]; then LIBS="${LIBS} ${TLS_LIBS}" fi -CFLAGS="${CFLAGS} '-DLIB_NAME=\"${LIB_NAME}\"' '-DLIB_VERSION=\"${LIB_VERSION}\"' ${DEBUG}" -LDFLAGS="${LIBS} ${LD_EXTRA}" +CFLAGS="${CFLAGS} '-DLIB_NAME=\"${LIB_NAME}\"' ${DEBUG}" +LDFLAGS="${LIBS} ${LDFLAGS}" # # Makefile generation @@ -128,11 +137,27 @@ print_obj() { printf '%s ' "$2" } +get_deps() { + src="$1" + + ${CC} -I${INCLUDE} -E "$src" \ + | grep '^#' \ + | awk '{print $3}' \ + | cut -d '"' -f 2 \ + | sort \ + | uniq \ + | grep -v '^[/<]' \ + | grep "^${SRC}/" \ + | while IFS= read -r dep; do + printf "%s " "$dep" + done +} + compile_obj() { src="$1" obj="$2" - ${CC} -I${INCLUDE} -MM -MT "${obj}" "${src}" + echo "${obj}: $(get_deps ${src})" echo "${TAB}@mkdir -p $(dirname ${obj})" echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\"" } @@ -143,16 +168,13 @@ compile_bin() { echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${src}" echo "${TAB}@mkdir -p ${OUT}/bin" - echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME} ${STATIC}" + echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME}" } compile_doc() { src="$1" out="$2" - - if [ -z "${STATIC}" ]; then - pref="LD_LIBRARY_PATH=${OUT}/lib " - fi + pref="LD_LIBRARY_PATH=${OUT}/lib " echo "${out}: ${OUT}/bin/hdoc ${src}" echo "${TAB}@mkdir -p ${OUT}/man/man3" diff --git a/src/Array.c b/src/Array.c index 911258e..d16db3f 100644 --- a/src/Array.c +++ b/src/Array.c @@ -38,12 +38,12 @@ struct Array size_t size; /* Elements actually filled */ }; -int +bool ArrayAdd(Array * array, void *value) { if (!array) { - return 0; + return false; } return ArrayInsert(array, array->size, value); @@ -122,14 +122,14 @@ ArrayGet(Array * array, size_t index) } -extern int +bool ArrayInsert(Array * array, size_t index, void *value) { size_t i; if (!array || !value || index > array->size) { - return 0; + return false; } if (array->size >= array->allocated) @@ -145,7 +145,7 @@ ArrayInsert(Array * array, size_t index, void *value) if (!array->entries) { array->entries = tmp; - return 0; + return false; } array->allocated = newSize; @@ -160,7 +160,7 @@ ArrayInsert(Array * array, size_t index, void *value) array->entries[index] = value; - return 1; + return true; } extern void * @@ -200,14 +200,14 @@ ArraySize(Array * array) return array->size; } -int +bool ArrayTrim(Array * array) { void **tmp; if (!array) { - return 0; + return false; } tmp = array->entries; @@ -218,10 +218,10 @@ ArrayTrim(Array * array) if (!array->entries) { array->entries = tmp; - return 0; + return false; } - return 1; + return true; } static void diff --git a/src/Base64.c b/src/Base64.c index fc43be8..ec81935 100644 --- a/src/Base64.c +++ b/src/Base64.c @@ -212,7 +212,7 @@ Base64Unpad(char *base64, size_t length) base64[length] = '\0'; } -extern int +bool Base64Pad(char **base64Ptr, size_t length) { char *tmp; @@ -221,7 +221,7 @@ Base64Pad(char **base64Ptr, size_t length) if (length % 4 == 0) { - return length; /* Success: no padding needed */ + return true; /* Success: no padding needed */ } newSize = length + (4 - (length % 4)); @@ -229,7 +229,7 @@ Base64Pad(char **base64Ptr, size_t length) tmp = Realloc(*base64Ptr, newSize + 100);; if (!tmp) { - return 0; /* Memory error */ + return false; /* Memory error */ } *base64Ptr = tmp; @@ -240,5 +240,5 @@ Base64Pad(char **base64Ptr, size_t length) (*base64Ptr)[newSize] = '\0'; - return newSize; + return true; } diff --git a/src/Cron.c b/src/Cron.c index df82b70..dd820ba 100644 --- a/src/Cron.c +++ b/src/Cron.c @@ -23,32 +23,33 @@ */ #include -#include #include #include #include +#include + #include struct Cron { - UInt64 tick; + uint64_t tick; Array *jobs; pthread_mutex_t lock; - volatile unsigned int stop:1; pthread_t thread; + volatile bool stop; }; typedef struct Job { - UInt64 interval; - UInt64 lastExec; + uint64_t interval; + uint64_t lastExec; JobFunc *func; void *args; } Job; static Job * -JobCreate(UInt32 interval, JobFunc * func, void *args) +JobCreate(uint64_t interval, JobFunc * func, void *args) { Job *job; @@ -63,8 +64,8 @@ JobCreate(UInt32 interval, JobFunc * func, void *args) return NULL; } - job->interval = UInt64Create(0, interval); - job->lastExec = UInt64Create(0, 0); + job->interval = interval; + job->lastExec = 0; job->func = func; job->args = args; @@ -79,51 +80,51 @@ CronThread(void *args) while (!cron->stop) { size_t i; - UInt64 ts; /* tick start */ - UInt64 te; /* tick end */ + uint64_t ts; /* tick start */ + uint64_t te; /* tick end */ pthread_mutex_lock(&cron->lock); - ts = UtilServerTs(); + ts = UtilTsMillis(); for (i = 0; i < ArraySize(cron->jobs); i++) { Job *job = ArrayGet(cron->jobs, i); - if (UInt64Gt(UInt64Sub(ts, job->lastExec), job->interval)) + if ((ts - job->lastExec) > job->interval) { job->func(job->args); job->lastExec = ts; } - if (UInt64Eq(job->interval, UInt64Create(0, 0))) + if (!job->interval) { ArrayDelete(cron->jobs, i); Free(job); } } - te = UtilServerTs(); + te = UtilTsMillis(); pthread_mutex_unlock(&cron->lock); - /* Only sleep if the jobs didn't overrun the tick */ - if (UInt64Gt(cron->tick, UInt64Sub(te, ts))) + // Only sleep if the jobs didn't overrun the tick + if (cron->tick > (te - ts)) { - const UInt64 microTick = UInt64Create(0, 100); + const uint64_t microTick = 100; - UInt64 remainingTick = UInt64Sub(cron->tick, UInt64Sub(te, ts)); + uint64_t remainingTick = cron->tick - (te - ts); /* Only sleep for microTick ms at a time because if the job * scheduler is supposed to stop before the tick is up, we * don't want to be stuck in a long sleep */ - while (UInt64Geq(remainingTick, microTick) && !cron->stop) + while (remainingTick >= microTick && !cron->stop) { UtilSleepMillis(microTick); - remainingTick = UInt64Sub(remainingTick, microTick); + remainingTick -= microTick; } - if (UInt64Neq(remainingTick, UInt64Create(0, 0)) && !cron->stop) + if (remainingTick && !cron->stop) { UtilSleepMillis(remainingTick); } @@ -134,7 +135,7 @@ CronThread(void *args) } Cron * -CronCreate(UInt32 tick) +CronCreate(uint64_t tick) { Cron *cron = Malloc(sizeof(Cron)); @@ -150,8 +151,8 @@ CronCreate(UInt32 tick) return NULL; } - cron->tick = UInt64Create(0, tick); - cron->stop = 1; + cron->tick = tick; + cron->stop = true; pthread_mutex_init(&cron->lock, NULL); @@ -180,7 +181,7 @@ CronOnce(Cron * cron, JobFunc * func, void *args) } void -CronEvery(Cron * cron, unsigned long interval, JobFunc * func, void *args) +CronEvery(Cron * cron, uint64_t interval, JobFunc * func, void *args) { Job *job; @@ -208,7 +209,7 @@ CronStart(Cron * cron) return; } - cron->stop = 0; + cron->stop = false; pthread_create(&cron->thread, NULL, CronThread, cron); } @@ -221,7 +222,7 @@ CronStop(Cron * cron) return; } - cron->stop = 1; + cron->stop = true; pthread_join(cron->thread, NULL); } diff --git a/src/Cytoplasm.c b/src/Cytoplasm.c index 43ff294..8c435c4 100644 --- a/src/Cytoplasm.c +++ b/src/Cytoplasm.c @@ -24,12 +24,22 @@ #include -char *CytoplasmGetName() +int +CytoplasmGetVersion(void) { - return LIB_NAME; + return CYTOPLASM_VERSION; } -char *CytoplasmGetVersion() +const char * +CytoplasmGetVersionStr(void) { - return LIB_VERSION; -} \ No newline at end of file + return "v" STRINGIFY(CYTOPLASM_VERSION_MAJOR) + "." STRINGIFY(CYTOPLASM_VERSION_MINOR) + "." STRINGIFY(CYTOPLASM_VERSION_PATCH) +#if CYTOPLASM_VERSION_ALPHA + "-alpha" STRINGIFY(CYTOPLASM_VERSION_ALPHA) +#elif CYTOPLASM_VERSION_BETA + "-beta" STRINGIFY(CYTOPLASM_VERSION_BETA) +#endif + ; +} diff --git a/src/Db.c b/src/Db.c index 41b329f..4d2983a 100644 --- a/src/Db.c +++ b/src/Db.c @@ -23,7 +23,6 @@ */ #include -#include #include #include #include @@ -77,7 +76,7 @@ struct DbRef { HashMap *json; - UInt64 ts; + uint64_t ts; size_t size; Array *name; @@ -495,12 +494,12 @@ DbLockFromArr(Db * db, Array * args) if (ref) /* In cache */ { - UInt64 diskTs = UtilLastModified(file); + uint64_t diskTs = UtilLastModified(file); ref->fd = fd; ref->stream = stream; - if (UInt64Gt(diskTs, ref->ts)) + if (diskTs > ref->ts) { /* File was modified on disk since it was cached */ HashMap *json = JsonDecode(ref->stream); @@ -588,7 +587,7 @@ DbLockFromArr(Db * db, Array * args) if (db->cache) { - ref->ts = UtilServerTs(); + ref->ts = UtilTsMillis(); ref->size = DbComputeSize(ref->json); HashMapSet(db->cache, hash, ref); db->cacheSize += ref->size; @@ -652,7 +651,7 @@ DbCreate(Db * db, size_t nArgs,...) file = DbFileName(db, args); - if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0))) + if (UtilLastModified(file)) { Free(file); ArrayFree(args); @@ -694,19 +693,19 @@ DbCreate(Db * db, size_t nArgs,...) return ret; } -int +bool DbDelete(Db * db, size_t nArgs,...) { va_list ap; Array *args; char *file; char *hash; - int ret = 1; + bool ret = true; DbRef *ref; if (!db) { - return 0; + return false; } va_start(ap, nArgs); @@ -755,9 +754,9 @@ DbDelete(Db * db, size_t nArgs,...) Free(hash); - if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0))) + if (UtilLastModified(file)) { - ret = remove(file) == 0; + ret = (remove(file) == 0); } pthread_mutex_unlock(&db->lock); @@ -790,14 +789,14 @@ DbLock(Db * db, size_t nArgs,...) return ret; } -int +bool DbUnlock(Db * db, DbRef * ref) { - int destroy; + bool destroy; if (!db || !ref) { - return 0; + return false; } lseek(ref->fd, 0L, SEEK_SET); @@ -806,7 +805,7 @@ DbUnlock(Db * db, DbRef * ref) pthread_mutex_unlock(&db->lock); Log(LOG_ERR, "Failed to truncate file on disk."); Log(LOG_ERR, "Error on fd %d: %s", ref->fd, strerror(errno)); - return 0; + return false; } JsonEncode(ref->json, ref->stream, JSON_DEFAULT); @@ -827,18 +826,18 @@ DbUnlock(Db * db, DbRef * ref) * require some items to be evicted. */ DbCacheEvict(db); - destroy = 0; + destroy = false; } else { - destroy = 1; + destroy = true; } Free(key); } else { - destroy = 1; + destroy = true; } if (destroy) @@ -850,16 +849,16 @@ DbUnlock(Db * db, DbRef * ref) } pthread_mutex_unlock(&db->lock); - return 1; + return true; } -int +bool DbExists(Db * db, size_t nArgs,...) { va_list ap; Array *args; char *file; - int ret; + bool ret; va_start(ap, nArgs); args = ArrayFromVarArgs(nArgs, ap); @@ -867,13 +866,13 @@ DbExists(Db * db, size_t nArgs,...) if (!args) { - return 0; + return false; } pthread_mutex_lock(&db->lock); file = DbFileName(db, args); - ret = UInt64Neq(UtilLastModified(file), UInt64Create(0, 0)); + ret = (UtilLastModified(file) != 0); pthread_mutex_unlock(&db->lock); @@ -955,15 +954,15 @@ DbJson(DbRef * ref) return ref ? ref->json : NULL; } -int +bool DbJsonSet(DbRef * ref, HashMap * json) { if (!ref || !json) { - return 0; + return false; } JsonFree(ref->json); ref->json = JsonDuplicate(json); - return 1; + return true; } diff --git a/src/HashMap.c b/src/HashMap.c index 424939b..d158b3f 100644 --- a/src/HashMap.c +++ b/src/HashMap.c @@ -247,12 +247,12 @@ HashMapGet(HashMap * map, const char *key) return NULL; } -int +bool HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i) { if (!map) { - return 0; + return false; } if (*i >= map->capacity) @@ -260,7 +260,7 @@ HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i) *i = 0; *key = NULL; *value = NULL; - return 0; + return false; } while (*i < map->capacity) @@ -273,20 +273,20 @@ HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i) { *key = bucket->key; *value = bucket->value; - return 1; + return true; } } *i = 0; - return 0; + return false; } -int +bool HashMapIterate(HashMap * map, char **key, void **value) { if (!map) { - return 0; + return false; } else { diff --git a/src/HttpClient.c b/src/HttpClient.c index 142ac81..88d7179 100644 --- a/src/HttpClient.c +++ b/src/HttpClient.c @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -154,7 +155,7 @@ HttpRequest(HttpRequestMethod method, int flags, unsigned short port, char *host HttpRequestMethodToString(method), path); HttpRequestHeader(context, "Connection", "close"); - HttpRequestHeader(context, "User-Agent", LIB_NAME "/" LIB_VERSION); + HttpRequestHeader(context, "User-Agent", LIB_NAME "/" STRINGIFY(CYTOPLASM_VERSION)); HttpRequestHeader(context, "Host", host); return context; diff --git a/src/HttpRouter.c b/src/HttpRouter.c index 02e6213..7777fcd 100644 --- a/src/HttpRouter.c +++ b/src/HttpRouter.c @@ -143,7 +143,7 @@ HttpRouterFree(HttpRouter * router) Free(router); } -int +bool HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec) { RouteNode *node; @@ -152,19 +152,19 @@ HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec) if (!router || !regPath || !exec) { - return 0; + return false; } if (StrEquals(regPath, "/")) { router->root->exec = exec; - return 1; + return true; } regPath = StrDuplicate(regPath); if (!regPath) { - return 0; + return false; } tmp = regPath; @@ -187,10 +187,10 @@ HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec) Free(regPath); - return 1; + return true; } -int +bool HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) { RouteNode *node; @@ -199,17 +199,17 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) HttpRouteFunc *exec = NULL; Array *matches = NULL; size_t i; - int retval; + bool retval; if (!router || !path) { - return 0; + return false; } matches = ArrayCreate(); if (!matches) { - return 0; + return false; } node = router->root; @@ -280,7 +280,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) if (!exec) { - retval = 0; + retval = false; goto finish; } @@ -293,7 +293,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret) exec(matches, args); } - retval = 1; + retval = true; finish: for (i = 0; i < ArraySize(matches); i++) diff --git a/src/HttpServer.c b/src/HttpServer.c index 0740e4b..b2a9535 100644 --- a/src/HttpServer.c +++ b/src/HttpServer.c @@ -465,7 +465,7 @@ HttpServerWorkerThread(void *args) ssize_t i = 0; HttpRequestMethod requestMethod; - UInt64 firstRead; + uint64_t firstRead; fp = DequeueConnection(server); @@ -473,7 +473,7 @@ HttpServerWorkerThread(void *args) { /* Block for 1 millisecond before continuing so we don't * murder the CPU if the queue is empty. */ - UtilSleepMillis(UInt64Create(0, 1)); + UtilSleepMillis(1); continue; } @@ -483,21 +483,25 @@ HttpServerWorkerThread(void *args) * happens, UtilGetLine() sets errno to EAGAIN. If we get * EAGAIN, then clear the error on the stream and try again * after a few ms. This is typically more than enough time for - * the client to send data. */ - firstRead = UtilServerTs(); + * the client to send data. + * + * TODO: Instead of looping, abort immediately, and place the request + * at the end of the queue. + */ + firstRead = UtilTsMillis(); while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1 && errno == EAGAIN) { StreamClearError(fp); - /* If the server is stopped, or it's been a while, just - * give up so we aren't wasting a thread on this client. */ - if (server->stop || UInt64Gt(UInt64Sub(UtilServerTs(), firstRead), UInt64Create(0, 1000 * 30))) + // If the server is stopped, or it's been a while, just + // give up so we aren't wasting a thread on this client. + if (server->stop || (UtilTsMillis() - firstRead) > (1000 * 30)) { goto finish; } - UtilSleepMillis(UInt64Create(0, 5)); + UtilSleepMillis(5); } if (lineLen == -1) @@ -711,25 +715,25 @@ HttpServerEventThread(void *args) return NULL; } -int +bool HttpServerStart(HttpServer * server) { if (!server) { - return 0; + return false; } if (server->isRunning) { - return 1; + return true; } if (pthread_create(&server->socketThread, NULL, HttpServerEventThread, server) != 0) { - return 0; + return false; } - return 1; + return true; } void diff --git a/src/Int64.c b/src/Int64.c deleted file mode 100644 index 21f07f5..0000000 --- a/src/Int64.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> - * - * 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 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 -#include - -#include - -#ifdef INT64_NATIVE -#define Int64Sign(x) ((int) (((UInt64) (x)) >> 63)) -#else -#define Int64Sign(x) ((int) ((x).i[1] >> 31)) -#endif - -size_t -Int64Str(Int64 x, int base, char *out, size_t len) -{ - static const char symbols[] = "0123456789ABCDEF"; - - size_t i = len - 1; - size_t j = 0; - - int neg = Int64Sign(x); - - Int64 base64 = Int64Create(0, base); - - /* We only have symbols up to base 16 */ - if (base < 2 || base > 16) - { - return 0; - } - - /* - * This algorithm doesn't work on INT64_MIN. - * - * But it works on all other integers in the range, so we - * just scoot the range in by one for now. It's a hack and - * I'm not a huge fan of it, but this function is mostly - * used in Json, which shouldn't have a range this large - * anyway (Json is limited to -2^53 -> 2^53-1). - * - * Proper fixes are always welcome. - */ - if (Int64Eq(x, Int64Create(0x80000000, 0x00000000))) - { - x = Int64Add(x, Int64Create(0, 1)); - } -#if 0 - else if (Int64Eq(x, Int64Create(0x7FFFFFFF, 0xFFFFFFFF))) - { - x = Int64Sub(x, Int64Create(0, 1)); - } -#endif - - if (base != 2 && base != 8 && base != 16 && neg) - { - x = Int64Neg(x); - } - - do - { - Int64 mod = Int64Rem(x, base64); - Int32 low = Int64Low(mod); - - out[i] = symbols[low]; - i--; - x = Int64Div(x, base64); - } while (Int64Gt(x, Int64Create(0, 0))); - - if (base != 2 && base != 8 && base != 16) - { - /* - * Binary, octal, and hexadecimal are known to - * be bit representations. Everything else (notably - * decimal) should include the negative sign. - */ - if (neg) - { - out[i] = '-'; - i--; - } - } - - while (++i < len) - { - out[j++] = out[i]; - } - - out[j] = '\0'; - - return j; -} - -#ifndef INT64_NATIVE - -/* No native 64-bit support, add our own */ - -Int64 -Int64Create(UInt32 high, UInt32 low) -{ - Int64 x; - - x.i[0] = low; - x.i[1] = high; - - return x; -} - -Int64 -Int64Add(Int64 x, Int64 y) -{ - Int64 z = Int64Create(0, 0); - int carry; - - z.i[0] = x.i[0] + y.i[0]; - carry = z.i[0] < x.i[0]; - z.i[1] = x.i[1] + y.i[1] + carry; - - return z; -} - -Int64 -Int64Sub(Int64 x, Int64 y) -{ - return Int64Add(x, Int64Neg(y)); -} - -Int64 -Int64Mul(Int64 x, Int64 y) -{ - Int64 z = Int64Create(0, 0); - - int xneg = Int64Sign(x); - int yneg = Int64Sign(y); - - if (xneg) - { - x = Int64Neg(x); - } - - if (yneg) - { - y = Int64Neg(y); - } - - /* while (y > 0) */ - while (Int64Gt(y, Int64Create(0, 0))) - { - /* if (y & 1 != 0) */ - if (Int64Neq(Int64And(y, Int64Create(0, 1)), Int64Create(0, 0))) - { - z = Int64Add(z, x); - } - - x = Int64Sll(x, 1); - y = Int64Sra(y, 1); - } - - if (xneg != yneg) - { - z = Int64Neg(z); - } - - return z; -} - -typedef struct -{ - Int64 q; - Int64 r; -} Int64Ldiv; - -static Int64Ldiv -Int64LongDivision(Int64 n, Int64 d) -{ - Int64Ldiv o; - - int i; - - int nneg = Int64Sign(n); - int dneg = Int64Sign(d); - - o.q = Int64Create(0, 0); - o.r = Int64Create(0, 0); - - if (Int64Eq(d, Int64Create(0, 0))) - { - raise(SIGFPE); - return o; - } - - if (nneg) - { - n = Int64Neg(n); - } - - if (dneg) - { - d = Int64Neg(d); - } - - for (i = 63; i >= 0; i--) - { - Int64 bit = Int64And(Int64Sra(n, i), Int64Create(0, 1)); - - o.r = Int64Sll(o.r, 1); - o.r = Int64Or(o.r, bit); - - if (Int64Geq(o.r, d)) - { - o.r = Int64Sub(o.r, d); - o.q = Int64Or(o.q, Int64Sll(Int64Create(0, 1), i)); - } - } - - if (nneg != dneg) - { - o.r = Int64Neg(o.r); - o.q = Int64Neg(o.q); - } - - return o; -} - -Int64 -Int64Div(Int64 x, Int64 y) -{ - return Int64LongDivision(x, y).q; -} - -Int64 -Int64Rem(Int64 x, Int64 y) -{ - return Int64LongDivision(x, y).r; -} - -Int64 -Int64Sll(Int64 x, int y) -{ - Int64 z; - - if (!y) - { - return x; - } - - z = Int64Create(0, 0); - - if (y < 32) - { - z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y); - z.i[0] = x.i[0] << y; - } - else - { - z.i[1] = x.i[0] << (y - 32); - } - - return z; -} - -Int64 -Int64Sra(Int64 x, int y) -{ - Int64 z; - - int neg = Int64Sign(x); - - if (!y) - { - return x; - } - - z = Int64Create(0, 0); - - if (y < 32) - { - z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y); - z.i[1] = x.i[1] >> y; - } - else - { - z.i[0] = x.i[1] >> (y - 32); - } - - if (neg) - { - Int64 mask = Int64Create(0xFFFFFFFF, 0xFFFFFFFF); - - z = Int64Or(Int64Sll(mask, (64 - y)), z); - } - - return z; -} - -Int64 -Int64And(Int64 x, Int64 y) -{ - return Int64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]); -} - -Int64 -Int64Or(Int64 x, Int64 y) -{ - return Int64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]); -} - -Int64 -Int64Xor(Int64 x, Int64 y) -{ - return Int64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]); -} - -Int64 -Int64Not(Int64 x) -{ - return Int64Create(~(x.i[1]), ~(x.i[0])); -} - -int -Int64Eq(Int64 x, Int64 y) -{ - return x.i[0] == y.i[0] && x.i[1] == y.i[1]; -} - -int -Int64Lt(Int64 x, Int64 y) -{ - int xneg = Int64Sign(x); - int yneg = Int64Sign(y); - - if (xneg != yneg) - { - return xneg > yneg; - } - else - { - if (xneg) - { - /* Both negative */ - return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]); - } - else - { - /* Both positive */ - return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]); - } - } -} - -int -Int64Gt(Int64 x, Int64 y) -{ - int xneg = Int64Sign(x); - int yneg = Int64Sign(y); - - if (xneg != yneg) - { - return xneg < yneg; - } - else - { - if (xneg) - { - /* Both negative */ - return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]); - } - else - { - /* Both positive */ - return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]); - } - } - -} - -#endif diff --git a/src/Json.c b/src/Json.c index 10a0316..3ff9880 100644 --- a/src/Json.c +++ b/src/Json.c @@ -26,14 +26,15 @@ #include #include #include -#include -#include #include #include #include #include #include +#include +#include + #include struct JsonValue @@ -44,9 +45,9 @@ struct JsonValue HashMap *object; Array *array; char *string; - Int64 integer; + uint64_t integer; double floating; - int boolean:1; + bool boolean; } as; }; @@ -201,7 +202,7 @@ JsonValueAsString(JsonValue * value) } JsonValue * -JsonValueInteger(Int64 integer) +JsonValueInteger(uint64_t integer) { JsonValue *value; @@ -217,12 +218,12 @@ JsonValueInteger(Int64 integer) return value; } -Int64 +uint64_t JsonValueAsInteger(JsonValue * value) { if (!value || value->type != JSON_INTEGER) { - return Int64Create(0, 0); + return 0; } return value->as.integer; @@ -258,7 +259,7 @@ JsonValueAsFloat(JsonValue * value) } JsonValue * -JsonValueBoolean(int boolean) +JsonValueBoolean(bool boolean) { JsonValue *value; @@ -274,12 +275,12 @@ JsonValueBoolean(int boolean) return value; } -int +bool JsonValueAsBoolean(JsonValue * value) { if (!value || value->type != JSON_BOOLEAN) { - return 0; + return false; } return value->as.boolean; @@ -335,12 +336,12 @@ JsonValueFree(JsonValue * value) Free(value); } -int +size_t JsonEncodeString(const char *str, Stream * out) { size_t i; char c; - int length = 0; + size_t length = 0; StreamPutc(out, '"'); length++; @@ -403,9 +404,9 @@ JsonDecodeString(Stream * in) int c; char a[5]; - UInt32 codepoint; - UInt16 high; - UInt16 low; + uint32_t codepoint; + uint16_t high; + uint16_t low; char *utf8Ptr; @@ -422,7 +423,7 @@ JsonDecodeString(Stream * in) { if (c <= 0x001F) { - /* Bad byte; these must be escaped */ + /* Bad byte; these must be escaped */ Free(str); return NULL; } @@ -598,15 +599,13 @@ JsonDecodeString(Stream * in) return NULL; } -int +size_t JsonEncodeValue(JsonValue * value, Stream * out, int level) { size_t i; size_t len; Array *arr; - int length = 0; - - char ibuf[INT64_STRBUF]; + size_t length = 0; switch (value->type) { @@ -644,8 +643,7 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level) length += JsonEncodeString(value->as.string, out); break; case JSON_INTEGER: - Int64Str(value->as.integer, 10, ibuf, INT64_STRBUF); - length += StreamPrintf(out, "%s", ibuf); + length += StreamPrintf(out, "%" PRId64, value->as.integer); break; case JSON_FLOAT: length += StreamPrintf(out, "%f", value->as.floating); @@ -673,14 +671,14 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level) return length; } -int +size_t JsonEncode(HashMap * object, Stream * out, int level) { size_t index; size_t count; char *key; JsonValue *value; - int length; + size_t length; if (!object) { @@ -863,6 +861,7 @@ JsonConsumeWhitespace(JsonParserState * state) break; } + // TODO: This logic should be moved into Stream as a sync function. if (StreamError(state->stream)) { if (errno == EAGAIN) @@ -876,7 +875,7 @@ JsonConsumeWhitespace(JsonParserState * state) } else { - UtilSleepMillis(UInt64Create(0, delay)); + UtilSleepMillis(delay); continue; } } @@ -1123,7 +1122,7 @@ JsonDecodeValue(JsonParserState * state) JsonValue *value; char *strValue; - Int64 iValue; + int64_t iValue; size_t i; int neg; @@ -1146,7 +1145,7 @@ JsonDecodeValue(JsonParserState * state) Free(strValue); break; case TOKEN_INTEGER: - iValue = Int64Create(0, 0); + iValue = 0; i = 0; neg = 0; @@ -1162,14 +1161,14 @@ JsonDecodeValue(JsonParserState * state) } d = state->token[i] - '0'; - iValue = Int64Mul(iValue, Int64Create(0, 10)); - iValue = Int64Add(iValue, Int64Create(0, d)); + iValue *= 10; + iValue += d; i++; } if (neg) { - iValue = Int64Neg(iValue); + iValue *= -1; } value = JsonValueInteger(iValue); break; diff --git a/src/Memory.c b/src/Memory.c index 7fb2f64..134505c 100644 --- a/src/Memory.c +++ b/src/Memory.c @@ -32,8 +32,6 @@ #include #include -#include - #ifndef MEMORY_TABLE_CHUNK #define MEMORY_TABLE_CHUNK 256 #endif @@ -50,12 +48,12 @@ struct MemoryInfo void *pointer; }; -#define MEM_BOUND_TYPE UInt32 +#define MEM_BOUND_TYPE uint32_t #define MEM_BOUND 0xDEADBEEF #define MEM_BOUND_LOWER(p) *((MEM_BOUND_TYPE *) p) -#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((UInt8 *) p) + x)) + 1) -#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(UInt8)) + (2 * sizeof(MEM_BOUND_TYPE))) +#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((uint8_t *) p) + x)) + 1) +#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(uint8_t)) + (2 * sizeof(MEM_BOUND_TYPE))) static pthread_mutex_t lock; static void (*hook) (MemoryAction, MemoryInfo *, void *) = MemoryDefaultHook; diff --git a/src/Queue.c b/src/Queue.c index dbb0595..db228d1 100644 --- a/src/Queue.c +++ b/src/Queue.c @@ -75,39 +75,39 @@ QueueFree(Queue * q) Free(q); } -int +bool QueueFull(Queue * q) { if (!q) { - return 0; + return false; } return ((q->front == q->rear + 1) || (q->front == 0 && q->rear == q->size - 1)); } -int +bool QueueEmpty(Queue * q) { if (!q) { - return 0; + return false; } - return q->front == q->size + 1; + return (q->front == (q->size + 1)); } -int +bool QueuePush(Queue * q, void *element) { if (!q || !element) { - return 0; + return false; } if (QueueFull(q)) { - return 0; + return false; } if (q->front == q->size + 1) @@ -126,7 +126,7 @@ QueuePush(Queue * q, void *element) q->items[q->rear] = element; - return 1; + return true; } void * diff --git a/src/Rand.c b/src/Rand.c index 6665aef..3ece67a 100644 --- a/src/Rand.c +++ b/src/Rand.c @@ -23,12 +23,12 @@ */ #include -#include -#include #include #include #include +#include + #include #include @@ -42,12 +42,12 @@ typedef struct RandState { - UInt32 mt[RAND_STATE_VECTOR_LENGTH]; + uint32_t mt[RAND_STATE_VECTOR_LENGTH]; int index; } RandState; static void -RandSeed(RandState * state, UInt32 seed) +RandSeed(RandState * state, uint32_t seed) { state->mt[0] = seed & 0xFFFFFFFF; @@ -57,12 +57,12 @@ RandSeed(RandState * state, UInt32 seed) } } -static UInt32 +static uint32_t RandGenerate(RandState * state) { - static const UInt32 mag[2] = {0x0, 0x9908B0DF}; + static const uint32_t mag[2] = {0x0, 0x9908B0DF}; - UInt32 result; + uint32_t result; if (state->index >= RAND_STATE_VECTOR_LENGTH || state->index < 0) { @@ -118,22 +118,22 @@ RandDestructor(void *p) /* This algorithm therefore computes N random numbers generally in O(N) * time, while being less biased. */ void -RandIntN(int *buf, size_t size, unsigned int max) +RandIntN(uint32_t *buf, size_t size, uint32_t max) { static pthread_key_t stateKey; - static int createdKey = 0; + static bool createdKey = false; /* Limit the range to banish all previously biased results */ - const int allowed = RAND_MAX - RAND_MAX % max; + const uint32_t allowed = RAND_MAX - RAND_MAX % max; RandState *state; - int tmp; + uint32_t tmp; size_t i; if (!createdKey) { pthread_key_create(&stateKey, RandDestructor); - createdKey = 1; + createdKey = true; } state = pthread_getspecific(stateKey); @@ -141,8 +141,8 @@ RandIntN(int *buf, size_t size, unsigned int max) if (!state) { /* Generate a seed from the system time, PID, and TID */ - UInt64 ts = UtilServerTs(); - UInt32 seed = UInt64Low(ts) ^ getpid() ^ (unsigned long) pthread_self(); + uint64_t ts = UtilTsMillis(); + uint32_t seed = ts ^ getpid() ^ (unsigned long) pthread_self(); state = Malloc(sizeof(RandState)); RandSeed(state, seed); @@ -164,10 +164,10 @@ RandIntN(int *buf, size_t size, unsigned int max) } /* Generate just 1 random number */ -int -RandInt(unsigned int max) +uint32_t +RandInt(uint32_t max) { - int val = 0; + uint32_t val = 0; RandIntN(&val, 1, max); return val; diff --git a/src/Runtime.c b/src/Runtime.c index e5218ba..9a69875 100644 --- a/src/Runtime.c +++ b/src/Runtime.c @@ -38,11 +38,11 @@ HexDump(size_t off, char *hexBuf, char *asciiBuf, void *args) if (hexBuf && asciiBuf) { - fprintf(report, "%04lx: %s | %s |\n", off, hexBuf, asciiBuf); + fprintf(report, "%04zx: %s | %s |\n", off, hexBuf, asciiBuf); } else { - fprintf(report, "%04lx\n", off); + fprintf(report, "%04zx\n", off); } } @@ -52,7 +52,7 @@ MemoryIterator(MemoryInfo * i, void *args) { FILE *report = args; - fprintf(report, "%s:%d: %lu bytes at %p\n", + fprintf(report, "%s:%d: %zu bytes at %p\n", MemoryInfoGetFile(i), MemoryInfoGetLine(i), MemoryInfoGetSize(i), MemoryInfoGetPointer(i)); @@ -107,7 +107,7 @@ GenerateMemoryReport(int argc, char **argv) fprintf(report, " '%s'", argv[i]); } fprintf(report, "\nDate: %s\n", tsBuffer); - fprintf(report, "Total Bytes: %lu\n", MemoryAllocated()); + fprintf(report, "Total Bytes: %zu\n", MemoryAllocated()); fprintf(report, "\n"); MemoryIterate(MemoryIterator, report); diff --git a/src/Sha/Sha1.c b/src/Sha/Sha1.c index 1df414e..edd250f 100644 --- a/src/Sha/Sha1.c +++ b/src/Sha/Sha1.c @@ -23,7 +23,6 @@ */ #include #include -#include #include @@ -31,10 +30,10 @@ #define LOAD32H(x, y) \ { \ - x = ((UInt32)((y)[0] & 255) << 24) | \ - ((UInt32)((y)[1] & 255) << 16) | \ - ((UInt32)((y)[2] & 255) << 8) | \ - ((UInt32)((y)[3] & 255)); \ + x = ((uint32_t)((y)[0] & 255) << 24) | \ + ((uint32_t)((y)[1] & 255) << 16) | \ + ((uint32_t)((y)[2] & 255) << 8) | \ + ((uint32_t)((y)[3] & 255)); \ } #define ROL(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) @@ -49,22 +48,22 @@ typedef union { - UInt8 c[64]; - UInt32 l[16]; + uint8_t c[64]; + uint32_t l[16]; } Char64Long16; typedef struct { - UInt32 state[5]; - UInt32 count[2]; - UInt8 buffer[64]; + uint32_t state[5]; + uint32_t count[2]; + uint8_t buffer[64]; } Sha1Context; static void -Sha1Transform(UInt32 state[5], const UInt8 buffer[64]) +Sha1Transform(uint32_t state[5], const uint8_t *buffer) { - UInt32 a, b, c, d, e, i; - UInt8 workspace[64]; + uint32_t a, b, c, d, e, i; + uint8_t workspace[64]; Char64Long16 *block = (Char64Long16 *) workspace; for (i = 0; i < 16; i++) @@ -180,9 +179,9 @@ Sha1Init(Sha1Context * ctx) } static void -Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size) +Sha1Update(Sha1Context * ctx, const void *buf, uint32_t size) { - UInt32 i, j; + uint32_t i, j; j = (ctx->count[0] >> 3) & 63; @@ -202,7 +201,7 @@ Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size) for (; i + 63 < size; i += 64) { - Sha1Transform(ctx->state, (UInt8 *) buf + i); + Sha1Transform(ctx->state, (uint8_t *) buf + i); } j = 0; @@ -212,14 +211,14 @@ Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size) i = 0; } - memcpy(&ctx->buffer[j], &((UInt8 *) buf)[i], size - i); + memcpy(&ctx->buffer[j], &((uint8_t *) buf)[i], size - i); } static void Sha1Calculate(Sha1Context * ctx, unsigned char *out) { - UInt32 i; - UInt8 count[8]; + uint32_t i; + uint8_t count[8]; for (i = 0; i < 8; i++) { @@ -227,16 +226,16 @@ Sha1Calculate(Sha1Context * ctx, unsigned char *out) >> ((3 - (i & 3)) * 8)) & 255); } - Sha1Update(ctx, (UInt8 *) "\x80", 1); + Sha1Update(ctx, (uint8_t *) "\x80", 1); while ((ctx->count[0] & 504) != 448) { - Sha1Update(ctx, (UInt8 *) "\0", 1); + Sha1Update(ctx, (uint8_t *) "\0", 1); } Sha1Update(ctx, count, 8); for (i = 0; i < (160 / 8); i++) { - out[i] = (UInt8) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + out[i] = (uint8_t) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } } diff --git a/src/Sha/Sha256.c b/src/Sha/Sha256.c index 3584f09..82ea046 100644 --- a/src/Sha/Sha256.c +++ b/src/Sha/Sha256.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include @@ -31,10 +30,10 @@ #include #define GET_UINT32(x) \ - (((UInt32)(x)[0] << 24) | \ - ((UInt32)(x)[1] << 16) | \ - ((UInt32)(x)[2] << 8) | \ - ((UInt32)(x)[3])) + (((uint32_t)(x)[0] << 24) | \ + ((uint32_t)(x)[1] << 16) | \ + ((uint32_t)(x)[2] << 8) | \ + ((uint32_t)(x)[3])) #define PUT_UINT32(dst, x) { \ (dst)[0] = (x) >> 24; \ @@ -56,8 +55,8 @@ #define WW(i) (w[i] = w[i - 16] + S0(w[i - 15]) + w[i - 7] + S1(w[i - 2])) #define ROUND(a, b, c, d, e, f, g, h, k, w) { \ - UInt32 tmp0 = h + T0(e) + CH(e, f, g) + k + w; \ - UInt32 tmp1 = T1(a) + MAJ(a, b, c); \ + uint32_t tmp0 = h + T0(e) + CH(e, f, g) + k + w; \ + uint32_t tmp1 = T1(a) + MAJ(a, b, c); \ h = tmp0 + tmp1; \ d += tmp0; \ } @@ -65,7 +64,7 @@ typedef struct Sha256Context { size_t length; - UInt32 state[8]; + uint32_t state[8]; size_t bufLen; unsigned char buffer[64]; } Sha256Context; @@ -73,7 +72,7 @@ typedef struct Sha256Context static void Sha256Chunk(Sha256Context * context, unsigned char chunk[64]) { - const UInt32 rk[64] = { + const uint32_t rk[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, @@ -87,8 +86,8 @@ Sha256Chunk(Sha256Context * context, unsigned char chunk[64]) 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; - UInt32 w[64]; - UInt32 a, b, c, d, e, f, g, h; + uint32_t w[64]; + uint32_t a, b, c, d, e, f, g, h; int i; @@ -178,10 +177,10 @@ Sha256(char *str) unsigned char *out; unsigned char fill[64]; - UInt32 fillLen; + uint32_t fillLen; unsigned char buf[8]; - UInt32 hiLen; - UInt32 loLen; + uint32_t hiLen; + uint32_t loLen; if (!str) { @@ -213,8 +212,8 @@ Sha256(char *str) fill[0] = 0x80; fillLen = (context.bufLen < 56) ? 56 - context.bufLen : 120 - context.bufLen; - hiLen = (UInt32) (context.length >> 29); - loLen = (UInt32) (context.length << 3); + hiLen = (uint32_t) (context.length >> 29); + loLen = (uint32_t) (context.length << 3); PUT_UINT32(&buf[0], hiLen); PUT_UINT32(&buf[4], loLen); diff --git a/src/Str.c b/src/Str.c index 2f4c665..bcbb63d 100644 --- a/src/Str.c +++ b/src/Str.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -35,8 +34,8 @@ #include #include -UInt32 -StrUtf16Decode(UInt16 high, UInt16 low) +uint32_t +StrUtf16Decode(uint16_t high, uint16_t low) { if (high <= 0xD7FF) { @@ -56,7 +55,7 @@ StrUtf16Decode(UInt16 high, UInt16 low) } char * -StrUtf8Encode(UInt32 codepoint) +StrUtf8Encode(uint32_t codepoint) { char *str; @@ -220,10 +219,10 @@ StrConcat(size_t nStr,...) return str; } -int +bool StrBlank(const char *str) { - int blank = 1; + bool blank = true; size_t i = 0; while (str[i]) @@ -245,7 +244,7 @@ StrRandom(size_t len) static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; char *str; - int *nums; + uint32_t *nums; size_t i; if (!len) @@ -260,7 +259,7 @@ StrRandom(size_t len) return NULL; } - nums = Malloc(len * sizeof(int)); + nums = Malloc(len * sizeof(uint32_t)); if (!nums) { Free(str); @@ -323,21 +322,21 @@ StrLower(char *str) return ret; } -int +bool StrEquals(const char *str1, const char *str2) { /* Both strings are NULL, they're equal */ if (!str1 && !str2) { - return 1; + return true; } /* One or the other is NULL, they're not equal */ if (!str1 || !str2) { - return 0; + return false; } /* Neither are NULL, do a regular string comparison */ - return strcmp(str1, str2) == 0; + return (strcmp(str1, str2) == 0); } diff --git a/src/Stream.c b/src/Stream.c index 7c582af..539ec20 100644 --- a/src/Stream.c +++ b/src/Stream.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -50,11 +49,11 @@ struct Stream { Io *io; - UInt8 *rBuf; + uint8_t *rBuf; size_t rLen; size_t rOff; - UInt8 *wBuf; + uint8_t *wBuf; size_t wLen; char *ugBuf; @@ -550,13 +549,13 @@ StreamSeek(Stream * stream, off_t offset, int whence) return result; } -int +bool StreamEof(Stream * stream) { return stream && (stream->flags & STREAM_EOF); } -int +bool StreamError(Stream * stream) { return stream && (stream->flags & STREAM_ERR); @@ -626,7 +625,7 @@ StreamCopy(Stream * in, Stream * out) } else { - UtilSleepMillis(UInt64Create(0, STREAM_DELAY)); + UtilSleepMillis(STREAM_DELAY); continue; } } diff --git a/src/UInt64.c b/src/UInt64.c deleted file mode 100644 index ae8eff7..0000000 --- a/src/UInt64.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> - * - * 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 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 -#include - -size_t -UInt64Str(UInt64 x, int base, char *out, size_t len) -{ - static const char symbols[] = "0123456789ABCDEF"; - - size_t i = len - 1; - size_t j = 0; - - UInt64 base64 = UInt64Create(0, base); - - /* We only have symbols up to base 16 */ - if (base < 2 || base > 16) - { - return 0; - } - - do - { - UInt64 mod = UInt64Rem(x, base64); - UInt32 low = UInt64Low(mod); - - out[i] = symbols[low]; - i--; - x = UInt64Div(x, base64); - } while (UInt64Gt(x, UInt64Create(0, 0))); - - while (++i < len) - { - out[j++] = out[i]; - } - - out[j] = '\0'; - - return j; -} - -#ifndef UINT64_NATIVE - -/* No native 64-bit support, add our own */ - -UInt64 -UInt64Create(UInt32 high, UInt32 low) -{ - UInt64 x; - - x.i[0] = low; - x.i[1] = high; - - return x; -} - -UInt64 -UInt64Add(UInt64 x, UInt64 y) -{ - UInt64 z = UInt64Create(0, 0); - int carry; - - z.i[0] = x.i[0] + y.i[0]; - carry = z.i[0] < x.i[0]; - z.i[1] = x.i[1] + y.i[1] + carry; - - return z; -} - -UInt64 -UInt64Sub(UInt64 x, UInt64 y) -{ - UInt64 twosCompl = UInt64Add(UInt64Not(y), UInt64Create(0, 1)); - - return UInt64Add(x, twosCompl); -} - -UInt64 -UInt64Mul(UInt64 x, UInt64 y) -{ - UInt64 z = UInt64Create(0, 0); - - /* while (y > 0) */ - while (UInt64Gt(y, UInt64Create(0, 0))) - { - /* if (y & 1 != 0) */ - if (UInt64Neq(UInt64And(y, UInt64Create(0, 1)), UInt64Create(0, 0))) - { - z = UInt64Add(z, x); - } - - x = UInt64Sll(x, 1); - y = UInt64Srl(y, 1); - } - - return z; -} - -typedef struct -{ - UInt64 q; - UInt64 r; -} UInt64Ldiv; - -static UInt64Ldiv -UInt64LongDivision(UInt64 n, UInt64 d) -{ - UInt64Ldiv o; - - int i; - - o.q = UInt64Create(0, 0); - o.r = UInt64Create(0, 0); - - if (UInt64Eq(d, UInt64Create(0, 0))) - { - raise(SIGFPE); - return o; - } - - for (i = 63; i >= 0; i--) - { - UInt64 bit = UInt64And(UInt64Srl(n, i), UInt64Create(0, 1)); - - o.r = UInt64Sll(o.r, 1); - o.r = UInt64Or(o.r, bit); - - if (UInt64Geq(o.r, d)) - { - o.r = UInt64Sub(o.r, d); - o.q = UInt64Or(o.q, UInt64Sll(UInt64Create(0, 1), i)); - } - } - - return o; -} - -UInt64 -UInt64Div(UInt64 x, UInt64 y) -{ - return UInt64LongDivision(x, y).q; -} - -UInt64 -UInt64Rem(UInt64 x, UInt64 y) -{ - return UInt64LongDivision(x, y).r; -} - -UInt64 -UInt64Sll(UInt64 x, int y) -{ - UInt64 z; - - if (!y) - { - return x; - } - - z = UInt64Create(0, 0); - - if (y < 32) - { - z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y); - z.i[0] = x.i[0] << y; - } - else - { - z.i[1] = x.i[0] << (y - 32); - } - - return z; -} - -UInt64 -UInt64Srl(UInt64 x, int y) -{ - UInt64 z; - - if (!y) - { - return x; - } - - z = UInt64Create(0, 0); - - if (y < 32) - { - z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y); - z.i[1] = x.i[1] >> y; - } - else - { - z.i[0] = x.i[1] >> (y - 32); - } - - return z; -} - -UInt64 -UInt64And(UInt64 x, UInt64 y) -{ - return UInt64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]); -} - -UInt64 -UInt64Or(UInt64 x, UInt64 y) -{ - return UInt64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]); -} - -UInt64 -UInt64Xor(UInt64 x, UInt64 y) -{ - return UInt64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]); -} - -UInt64 -UInt64Not(UInt64 x) -{ - return UInt64Create(~(x.i[1]), ~(x.i[0])); -} - -int -UInt64Eq(UInt64 x, UInt64 y) -{ - return x.i[0] == y.i[0] && x.i[1] == y.i[1]; -} - -int -UInt64Lt(UInt64 x, UInt64 y) -{ - return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]); -} - -int -UInt64Gt(UInt64 x, UInt64 y) -{ - return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]); -} - -#endif diff --git a/src/Util.c b/src/Util.c index 183c26e..6701eb7 100644 --- a/src/Util.c +++ b/src/Util.c @@ -40,8 +40,6 @@ #include #include -#include - #ifndef PATH_MAX #define PATH_MAX 256 #endif @@ -50,14 +48,14 @@ #define SSIZE_MAX LONG_MAX #endif -UInt64 -UtilServerTs(void) +uint64_t +UtilTsMillis(void) { struct timeval tv; - UInt64 ts; - UInt64 sec; - UInt64 usec; + uint64_t ts; + uint64_t sec; + uint64_t usec; gettimeofday(&tv, NULL); @@ -77,54 +75,31 @@ UtilServerTs(void) * * The same goes for suseconds_t. */ - if (sizeof(time_t) == sizeof(UInt64)) - { - /* 64 bit time_t: convert it to a 64 bit integer */ - time_t ms = tv.tv_sec * 1000; - UInt32 high = (UInt32) (ms >> 32); - UInt32 low = (UInt32) ms; - sec = UInt64Create(high, low); - } - else - { - /* Assume 32 bit time_t: promote to 64 bit, then multiply, in - * case multiplication overflows 32 bits. */ - sec = UInt64Create(0, tv.tv_sec); - sec = UInt64Mul(sec, UInt64Create(0, 1000)); - } + // Two separate steps because time_t might be 32-bit. In that + // case, we want the multiplication to happen after the promotion + // to uint64_t. + sec = tv.tv_sec; + sec *= 1000; - usec = UInt64Create(0, tv.tv_usec / 1000); - ts = UInt64Add(sec, usec); + usec = tv.tv_usec / 1000; + + ts = sec + usec; return ts; } -UInt64 +uint64_t UtilLastModified(char *path) { struct stat st; - UInt64 ts = UInt64Create(0, 0); + uint64_t ts = 0; if (stat(path, &st) == 0) { - if (sizeof(time_t) == sizeof(UInt64)) - { - /* 64 bit time_t: convert it to a 64 bit integer */ - time_t ms = st.st_mtim.tv_sec * 1000; - UInt32 high = (UInt32) (ms >> 32); - UInt32 low = (UInt32) ms; - - ts = UInt64Create(high, low); - } - else - { - ts = UInt64Create(0, st.st_mtim.tv_sec); - ts = UInt64Mul(ts, UInt64Create(0, 1000)); - } - - /* nsec gauanteed to fit in 32 bits */ - ts = UInt64Add(ts, UInt64Create(0, st.st_mtim.tv_nsec / 1000000)); + ts = st.st_mtim.tv_sec; + ts *= 1000; + ts += st.st_mtim.tv_nsec / 1000000; } return ts; @@ -202,21 +177,13 @@ UtilMkdir(const char *dir, const mode_t mode) } int -UtilSleepMillis(UInt64 ms) +UtilSleepMillis(uint64_t ms) { struct timespec ts; int res; - if (sizeof(time_t) == sizeof(UInt64)) - { - ts.tv_sec = ((time_t) UInt64High(ms) << 32 | UInt64Low(ms)) / 1000; - } - else - { - ts.tv_sec = UInt64Low(ms) / 1000; - } - - ts.tv_nsec = UInt64Low(UInt64Rem(ms, UInt64Create(0, 1000))) * 1000000; + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; res = nanosleep(&ts, &ts); @@ -312,14 +279,14 @@ ThreadNoDestructor(void *p) free(p); } -UInt32 +uint32_t UtilThreadNo(void) { static pthread_key_t key; static int createdKey = 0; static unsigned long count = 0; - UInt32 *no; + uint32_t *no; if (!createdKey) { @@ -330,7 +297,7 @@ UtilThreadNo(void) no = pthread_getspecific(key); if (!no) { - no = malloc(sizeof(UInt32)); + no = malloc(sizeof(uint32_t)); *no = count++; pthread_setspecific(key, no); } diff --git a/src/include/Array.h b/src/include/Array.h index 0ba1335..0705b2b 100644 --- a/src/include/Array.h +++ b/src/include/Array.h @@ -52,6 +52,7 @@ #include #include +#include /** * The functions in this API operate on an array structure which is @@ -98,7 +99,7 @@ extern void *ArrayGet(Array *, size_t); * This function returns a boolean value indicating whether or not it * suceeded. */ -extern int ArrayInsert(Array *, size_t, void *); +extern bool ArrayInsert(Array *, size_t, void *); /** * Set the value at the specified index in the specified array to the @@ -115,7 +116,7 @@ extern void *ArraySet(Array *, size_t, void *); * return value as * .Fn ArrayInsert . */ -extern int ArrayAdd(Array *, void *); +extern bool ArrayAdd(Array *, void *); /** * Remove the element at the specified index from the specified array. @@ -146,7 +147,7 @@ extern void ArraySort(Array *, int (*) (void *, void *)); * .P * This is a relatively expensive operation. The array must first be * duplicated. Then it is sorted, then it is iterated from beginning - * to end to remove duplicate entires. Note that the comparison + * to end to remove duplicate entries. Note that the comparison * function is executed on each element at least twice. */ extern Array *ArrayUnique(Array *, int (*) (void *, void *)); @@ -167,7 +168,7 @@ extern Array *ArrayReverse(Array *); * array. This function is intended to be used by functions that return * relatively read-only arrays that will be long-lived. */ -extern int ArrayTrim(Array *); +extern bool ArrayTrim(Array *); /** * Convert a variadic arguments list into an Array. In most cases, the diff --git a/src/include/Base64.h b/src/include/Base64.h index b36a48c..74c8956 100644 --- a/src/include/Base64.h +++ b/src/include/Base64.h @@ -39,6 +39,7 @@ */ #include +#include /** * This function computes the amount of bytes needed to store a message @@ -93,7 +94,7 @@ extern void * this means it will only fail if a bigger string is necessary, but it * could not be automatically allocated on the heap. */ -extern int +extern bool Base64Pad(char **, size_t); #endif /* CYTOPLASM_BASE64_H */ diff --git a/src/include/Cron.h b/src/include/Cron.h index 23053c6..00280cc 100644 --- a/src/include/Cron.h +++ b/src/include/Cron.h @@ -24,6 +24,8 @@ #ifndef CYTOPLASM_CRON_H #define CYTOPLASM_CRON_H +#include + /*** * @Nm Cron * @Nd Basic periodic job scheduler. @@ -56,8 +58,6 @@ * by any means. */ -#include "Int.h" - /** * All functions defined here operate on a structure opaque to the * caller. @@ -82,7 +82,7 @@ typedef void (JobFunc) (void *); * .Pp * This function takes the tick interval in milliseconds. */ -extern Cron * CronCreate(UInt32); +extern Cron * CronCreate(uint64_t); /** * Schedule a one-off job to be executed only at the next tick, and @@ -110,7 +110,7 @@ extern void * and a pointer to pass to that function when it is executed. */ extern void - CronEvery(Cron *, unsigned long, JobFunc *, void *); + CronEvery(Cron *, uint64_t, JobFunc *, void *); /** * Start ticking the clock and executing registered jobs. diff --git a/src/include/Cytoplasm.h b/src/include/Cytoplasm.h index f965f2f..97a4a54 100644 --- a/src/include/Cytoplasm.h +++ b/src/include/Cytoplasm.h @@ -24,6 +24,17 @@ #ifndef CYTOPLASM_CYTOPLASM_H #define CYTOPLASM_CYTOPLASM_H +#define CYTOPLASM_VERSION_MAJOR 0 +#define CYTOPLASM_VERSION_MINOR 4 +#define CYTOPLASM_VERSION_PATCH 1 +#define CYTOPLASM_VERSION ((CYTOPLASM_VERSION_MAJOR * 10000) + (CYTOPLASM_VERSION_MINOR * 100) + (CYTOPLASM_VERSION_PATCH)) + +#define CYTOPLASM_VERSION_ALPHA 1 +#define CYTOPLASM_VERSION_BETA 0 +#define CYTOPLASM_VERSION_STABLE (!CYTOPLASM_VERSION_ALPHA && !CYTOPLASM_VERSION_BETA) + +#define STRINGIFY(x) #x + /*** * @Nm Cytoplasm * @Nd A simple API that provides metadata on the library itself. @@ -34,18 +45,8 @@ * currently loaded library. */ - -/** - * Get the name that this library was compiled with. In most cases, - * this will be hard-coded to "Cytoplasm", but it may differ if, for - * some reason, there exists another ABI-compatible library that - * wishes to report its name. - * - * This function really only exists because the information is - * available along side of the version information so for - * consistency, it made sense to include both. - */ -extern char * CytoplasmGetName(void); +/** */ +extern int CytoplasmGetVersion(void); /** * Get the library version. This will be useful mostly for printing @@ -55,6 +56,6 @@ extern char * CytoplasmGetName(void); * This function returns a string, which should usually be able to be * parsed using sscanf() if absolutely necessary. */ -extern char * CytoplasmGetVersion(void); +extern const char * CytoplasmGetVersionStr(void); -#endif /* CYTOPLASM_CYTOPLASM_H */ \ No newline at end of file +#endif /* CYTOPLASM_CYTOPLASM_H */ diff --git a/src/include/Db.h b/src/include/Db.h index da98a39..9aa0758 100644 --- a/src/include/Db.h +++ b/src/include/Db.h @@ -37,6 +37,7 @@ */ #include +#include #include "HashMap.h" #include "Array.h" @@ -113,7 +114,7 @@ extern DbRef * DbLock(Db *, size_t,...); * This function assumes the object is not locked, otherwise undefined * behavior will result. */ -extern int DbDelete(Db *, size_t,...); +extern bool DbDelete(Db *, size_t,...); /** * Unlock an object and return it back to the database. This function @@ -121,7 +122,7 @@ extern int DbDelete(Db *, size_t,...); * read cache; writes are always immediate to ensure data integrity in * the event of a system failure. */ -extern int DbUnlock(Db *, DbRef *); +extern bool DbUnlock(Db *, DbRef *); /** * Check the existence of the given database object in a more efficient @@ -130,7 +131,7 @@ extern int DbUnlock(Db *, DbRef *); * This function does not lock the object, nor does it load it into * memory if it exists. */ -extern int DbExists(Db *, size_t,...); +extern bool DbExists(Db *, size_t,...); /** * List all of the objects at a given path. Unlike the other varargs @@ -164,6 +165,6 @@ extern HashMap * DbJson(DbRef *); * replace it with new JSON. This is more efficient than duplicating * a separate object into the database reference. */ -extern int DbJsonSet(DbRef *, HashMap *); +extern bool DbJsonSet(DbRef *, HashMap *); #endif diff --git a/src/include/HashMap.h b/src/include/HashMap.h index f0ee7f3..716dacc 100644 --- a/src/include/HashMap.h +++ b/src/include/HashMap.h @@ -150,7 +150,7 @@ extern void * HashMapDelete(HashMap *, const char *); * insertions or deletions occur during the iteration. This * functionality has not been tested, and will likely not work. */ -extern int HashMapIterate(HashMap *, char **, void **); +extern bool HashMapIterate(HashMap *, char **, void **); /** * A reentrant version of @@ -163,7 +163,7 @@ extern int HashMapIterate(HashMap *, char **, void **); * .Pp * The cursor should be initialized to 0 at the start of iteration. */ -extern int +extern bool HashMapIterateReentrant(HashMap *, char **, void **, size_t *); /** diff --git a/src/include/HttpRouter.h b/src/include/HttpRouter.h index a0950b0..2df3db7 100644 --- a/src/include/HttpRouter.h +++ b/src/include/HttpRouter.h @@ -74,7 +74,7 @@ extern void HttpRouterFree(HttpRouter *); * .Pa /some/path/(.*)/parts * to work as one would expect. */ -extern int HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *); +extern bool HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *); /** * Route the specified request path using the specified routing @@ -86,6 +86,6 @@ extern int HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *); * how to handle, and the pointer to a void pointer is where the * route function's response will be placed. */ -extern int HttpRouterRoute(HttpRouter *, char *, void *, void **); +extern bool HttpRouterRoute(HttpRouter *, char *, void *, void **); #endif /* CYTOPLASM_HTTPROUTER_H */ diff --git a/src/include/HttpServer.h b/src/include/HttpServer.h index 78ef2f8..c539ac7 100644 --- a/src/include/HttpServer.h +++ b/src/include/HttpServer.h @@ -47,6 +47,7 @@ */ #include +#include #include "Http.h" #include "HashMap.h" @@ -133,7 +134,7 @@ extern void HttpServerFree(HttpServer *); * caller can continue working while the HTTP server is running in a * separate thread and managing a pool of threads to handle responses. */ -extern int HttpServerStart(HttpServer *); +extern bool HttpServerStart(HttpServer *); /** * Typically, at some point after calling diff --git a/src/include/Int.h b/src/include/Int.h deleted file mode 100644 index 7933a69..0000000 --- a/src/include/Int.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> - * - * 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 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 CYTOPLASM_INT_H -#define CYTOPLASM_INT_H - -/*** - * @Nm Int - * @Nd Fixed-width integer types. - * @Dd April 27 2023 - * - * This header provides cross-platform, fixed-width integer types. - * Specifically, it uses preprocessor magic to define the following - * types: - * .Bl -bullet -offset indent - * .It - * Int8 and UInt8 - * .It - * Int16 and UInt16 - * .It - * Int32 and UInt32 - * .El - * .Pp - * Note that there is no 64-bit integer type, because the ANSI C - * standard makes no guarantee that such a type will exist, even - * though it does on most platforms. - * .Pp - * The reason Cytoplasm provides its own header for this is - * because ANSI C does not define fixed-width types, and while it - * should be safe to rely on C99 fixed-width types in most cases, - * there may be cases where even that is not possible. - * - * @ignore-typedefs - */ - -#include - -#define BIT32_MAX 4294967295UL -#define BIT16_MAX 65535UL -#define BIT8_MAX 255UL - -#ifndef UCHAR_MAX -#error Size of char data type is unknown. Define UCHAR_MAX. -#endif - -#ifndef USHRT_MAX -#error Size of short data type is unknown. Define USHRT_MAX. -#endif - -#ifndef UINT_MAX -#error Size of int data type is unknown. Define UINT_MAX. -#endif - -#ifndef ULONG_MAX -#error Size of long data type is unknown. Define ULONG_MAX. -#endif - -#if UCHAR_MAX == BIT8_MAX -typedef signed char Int8; -typedef unsigned char UInt8; - -#else -#error Unable to determine suitable data type for 8-bit integers. -#endif - -#if UINT_MAX == BIT16_MAX -typedef signed int Int16; -typedef unsigned int UInt16; - -#elif USHRT_MAX == BIT16_MAX -typedef signed short Int16; -typedef unsigned short UInt16; - -#elif UCHAR_MAX == BIT16_MAX -typedef signed char Int16; -typedef unsigned char UInt16; - -#else -#error Unable to determine suitable data type for 16-bit integers. -#endif - -#if ULONG_MAX == BIT32_MAX -typedef signed long Int32; -typedef unsigned long UInt32; - -#elif UINT_MAX == BIT32_MAX -typedef signed int Int32; -typedef unsigned int UInt32; - -#elif USHRT_MAX == BIT32_MAX -typedef signed short Int32; -typedef unsigned short UInt32; - -#elif UCHAR_MAX == BIT32_MAX -typedef signed char Int32; -typedef unsigned char UInt32; - -#else -#error Unable to determine suitable data type for 32-bit integers. -#endif - -#endif /* CYTOPLASM_INT_H */ diff --git a/src/include/Int64.h b/src/include/Int64.h deleted file mode 100644 index e380ab4..0000000 --- a/src/include/Int64.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> - * - * 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 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 CYTOPLASM_INT64_H -#define CYTOPLASM_INT64_H - -/*** - * @Nm Int64 - * @Nd Fixed-width 64 bit integers. - * @Dd August 11, 2023 - * - * .Pp - * ANSI C89 (or C99 for that matter) provides no required mechanism - * for 64 bit integers. Nevertheless, many compilers provide them as - * extensions. However, since it is not a gaurantee, and to be fully - * standards-compliant and thus portable, a platform-agnostic interface - * is required. This header provides such an interface. If the platform - * has a 64 bit integer type, that is used, and native operations are - * performed by C preprocessor macro expansion. Otherwise, a - * compatibility layer is provided, which implements 64-bit - * arithmetic on an array of 2 32-bit numbers which are provided by - * .Xr Int 3 . - * .Pp - * Note that 64-bit emulation is certainly not as performant as using - * native 64-bit operations, so whenever possible, the native - * operations should be preferred. However, since C provides no required - * 64 bit integer on 32-bit and less platforms, this API can be used as - * a "good enough" fallback mechanism. - * .Pp - * Also note that this implementation, both in the native and - * non-native forms, makes some assumptions: - * .Bl -bullet -width Ds - * .It - * When a cast from a larger integer to a smaller integer is performed, - * the upper bits are truncated, not the lower bits. - * .It - * Negative numbers are represented in memory and in registers in two's - * compliment form. - * .El - * .Pp - * This API may provide unexpected output if these assumptions are - * false for a given platform. - * - * @ignore-typedefs - */ - -#include "Int.h" -#include "UInt64.h" - -#include - -#ifndef INT64_FORCE_EMULATED - -#define BIT64_MAX 18446744073709551615UL - -#if UINT_MAX == BIT64_MAX -typedef signed int Int64; - -#define INT64_NATIVE - -#elif ULONG_MAX == BIT64_MAX -typedef signed long Int64; - -#define INT64_NATIVE - -#endif - -#endif /* ifndef INT64_FORCE_EMULATED */ - -#ifdef INT64_NATIVE - -#define Int64Create(high, low) ((Int64) (((UInt64) (high) << 32) | (low))) -#define Int64Neg(x) (-(x)) - -#define Int64Low(a) ((UInt32) (a)) -#define Int64High(a) ((UInt32) ((a) >> 32)) - -#define Int64Add(a, b) ((a) + (b)) -#define Int64Sub(a, b) ((a) - (b)) -#define Int64Mul(a, b) ((a) * (b)) -#define Int64Div(a, b) ((a) / (b)) -#define Int64Rem(a, b) ((a) % (b)) - -#define Int64Sll(a, b) ((a) << (b)) -#define Int64Sra(a, b) ((a) >> (b)) - -#define Int64And(a, b) ((a) & (b)) -#define Int64Or(a, b) ((a) | (b)) -#define Int64Xor(a, b) ((a) ^ (b)) -#define Int64Not(a) (~(a)) - -#define Int64Eq(a, b) ((a) == (b)) -#define Int64Lt(a, b) ((a) < (b)) -#define Int64Gt(a, b) ((a) > (b)) - -#define Int64Neq(a, b) ((a) != (b)) -#define Int64Leq(a, b) ((a) <= (b)) -#define Int64Geq(a, b) ((a) >= (b)) - -#else - -#define Int64Neg(x) (Int64Add(Int64Not(x), Int64Create(0, 1))) - -/** - * The internal bit representation of a signed integer is identical - * to an unsigned integer, the difference is in the algorithms and - * the way the bits are interpreted. - */ -typedef UInt64 Int64; - -/** - * Create a new signed 64 bit integer using the given high and low - * bits. - */ -extern Int64 Int64Create(UInt32, UInt32); - -/** - * Add two signed 64 bit integers together. - */ -extern Int64 Int64Add(Int64, Int64); - -/** - * Subtract the second 64 bit integer from the first. - */ -extern Int64 Int64Sub(Int64, Int64); - -/** - * Multiply two 64 bit integers together. The non-native version of - * this function uses the Russian Peasant method of multiplication, - * which should afford more performance than a naive multiplication by - * addition, but it is still rather slow and depends on the size of - * the integers being multiplied. - */ -extern Int64 Int64Mul(Int64, Int64); - -/** - * Divide the first 64 bit integer by the second and return the - * quotient. The non-native version of this function uses naive binary - * long division, which is slow, but gauranteed to finish in constant - * time. - */ -extern Int64 Int64Div(Int64, Int64); - -/** - * Divide the first 64 bit integer by the second and return the - * remainder. The non-native version of this function uses naive binary - * long division, which is slow, but gauranteed to finish in constant - * time. - */ -extern Int64 Int64Rem(Int64, Int64); - -/** - * Perform a left logical bit shift of a 64 bit integer. The second - * parameter is how many places to shift, and is declared as a regular - * integer because anything more than 64 does not make sense. - */ -extern Int64 Int64Sll(Int64, int); - -/** - * Perform a right arithmetic bit shift of a 64 bit integer. The second - * parameter is how many places to shift, and is declared as a regular - * integer because anything more than 64 does not make sense. - * .Pp - * Note that on platforms that use the native 64-bit implementation, - * this is technically implementation-defined, and may in fact be a - * logical shift instead of an arithmetic shift. Note that typically - * this operation is not performed on signed integers. - */ -extern Int64 Int64Sra(Int64, int); - -/** - * Perform a bitwise AND (&) of the provided 64 bit integers. - */ -extern Int64 Int64And(Int64, Int64); - -/** - * Perform a bitwise OR (|) of the provided 64 bit integers. - */ -extern Int64 Int64Or(Int64, Int64); - -/** - * Perform a bitwise XOR (^) of the provided 64 bit integers. - */ -extern Int64 Int64Xor(Int64, Int64); - -/** - * Perform a bitwise NOT (~) of the provided 64 bit integer. - */ -extern Int64 Int64Not(Int64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if they are equal. - */ -extern int Int64Eq(Int64, Int64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if the second operand is strictly - * less than the first. - */ -extern int Int64Lt(Int64, Int64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if the second operand is strictly - * greater than the first. - */ -extern int Int64Gt(Int64, Int64); - -#define Int64Low(a) ((a).i[0]) -#define Int64High(a) ((a).i[1]) - -#define Int64Neq(a, b) (!Int64Eq(a, b)) -#define Int64Leq(a, b) (Int64Eq(a, b) || Int64Lt(a, b)) -#define Int64Geq(a, b) (Int64Eq(a, b) || Int64Gt(a, b)) - -#endif - -#define INT64_STRBUF 65 /* Base 2 representation with '\0' */ - -/** - * Convert a 64 bit integer to a string in an arbitrary base - * representation specified by the second parameter, using the provided - * buffer and length specified by the third and fourth parameters. To - * guarantee that the string will fit in the buffer, allocate it of - * size INT64_STRBUF or larger. Note that a buffer size smaller than - * INT64_STRBUF will invoke undefined behavior. - */ -extern size_t Int64Str(Int64, int, char *, size_t); - -#endif /* CYTOPLASM_INT64_H */ diff --git a/src/include/Json.h b/src/include/Json.h index 5a14aab..e74c77d 100644 --- a/src/include/Json.h +++ b/src/include/Json.h @@ -71,10 +71,10 @@ #include "HashMap.h" #include "Array.h" #include "Stream.h" -#include "Int64.h" #include #include +#include #define JSON_DEFAULT -1 #define JSON_PRETTY 0 @@ -152,7 +152,7 @@ extern char * JsonValueAsString(JsonValue *); * Encode a number as a JSON value that can be added to an object or * an array. */ -extern JsonValue * JsonValueInteger(Int64); +extern JsonValue * JsonValueInteger(uint64_t); /** * Unwrap a JSON value that represents a number. This function will @@ -160,7 +160,7 @@ extern JsonValue * JsonValueInteger(Int64); * misleading. Check the type of the value before making assumptions * about its value. */ -extern Int64 JsonValueAsInteger(JsonValue *); +extern uint64_t JsonValueAsInteger(JsonValue *); /** * Encode a floating point number as a JSON value that can be added @@ -181,7 +181,7 @@ extern double JsonValueAsFloat(JsonValue *); * expressions as a JSON value that can be added to an object or an * array. */ -extern JsonValue * JsonValueBoolean(int); +extern JsonValue * JsonValueBoolean(bool); /** * Unwrap a JSON value that represents a boolean. This function will @@ -189,7 +189,7 @@ extern JsonValue * JsonValueBoolean(int); * misleading. Check the type of the value before making assumptions * about its type. */ -extern int JsonValueAsBoolean(JsonValue *); +extern bool JsonValueAsBoolean(JsonValue *); /** * This is a special case that represents a JSON null. Because the @@ -253,7 +253,7 @@ extern void JsonFree(HashMap *); * or if the stream is NULL, the number of bytes that would have * been written. */ -extern int JsonEncodeString(const char *, Stream *); +extern size_t JsonEncodeString(const char *, Stream *); /** * Serialize a JSON value as it would appear in JSON output. This is @@ -277,7 +277,7 @@ extern int JsonEncodeString(const char *, Stream *); * or if the stream is NULL, the number of bytes that would have * been written. */ -extern int JsonEncodeValue(JsonValue *, Stream *, int); +extern size_t JsonEncodeValue(JsonValue *, Stream *, int); /** * Encode a JSON object as it would appear in JSON output, writing it @@ -289,7 +289,7 @@ extern int JsonEncodeValue(JsonValue *, Stream *, int); * or if the stream is NULL, the number of bytes that would have * been written. */ -extern int JsonEncode(HashMap *, Stream *, int); +extern size_t JsonEncode(HashMap *, Stream *, int); /** * Decode a JSON object from the given input stream and parse it into diff --git a/src/include/Memory.h b/src/include/Memory.h index 5d5ecec..d6836ee 100644 --- a/src/include/Memory.h +++ b/src/include/Memory.h @@ -76,6 +76,7 @@ * macros. */ #include +#include /** * These values are passed into the memory hook function to indicate diff --git a/src/include/Queue.h b/src/include/Queue.h index 35821d3..1c148b7 100644 --- a/src/include/Queue.h +++ b/src/include/Queue.h @@ -46,6 +46,7 @@ */ #include +#include /** * These functions operate on a queue structure that is opaque to the @@ -73,7 +74,7 @@ extern void QueueFree(Queue *); * value indicating whether or not the push succeeded. Pushing items * into the queue will fail if the queue is full. */ -extern int QueuePush(Queue *, void *); +extern bool QueuePush(Queue *, void *); /** * Pop an element out of the queue. This function returns NULL if the @@ -95,11 +96,11 @@ extern void * QueuePeek(Queue *); /** * Determine whether or not the queue is full. */ -extern int QueueFull(Queue *); +extern bool QueueFull(Queue *); /** * Determine whether or not the queue is empty. */ -extern int QueueEmpty(Queue *); +extern bool QueueEmpty(Queue *); #endif diff --git a/src/include/Rand.h b/src/include/Rand.h index a5be3ce..69fdb7f 100644 --- a/src/include/Rand.h +++ b/src/include/Rand.h @@ -58,11 +58,13 @@ */ #include +#include /** - * Generate a single random integer between 0 and the passed value. + * Generate a single random 32-bit integer between 0 and the + * passed value. */ -extern int RandInt(unsigned int); +extern uint32_t RandInt(uint32_t); /** * Generate the number of integers specified by the second argument @@ -76,6 +78,6 @@ extern int RandInt(unsigned int); * has to lock and unlock a mutex. It is therefore better to obtain * multiple random numbers in one pass if multiple are needed. */ -extern void RandIntN(int *, size_t, unsigned int); +extern void RandIntN(uint32_t *, size_t, uint32_t); #endif /* CYTOPLASM_RAND_H */ diff --git a/src/include/Str.h b/src/include/Str.h index cae9062..87bc92b 100644 --- a/src/include/Str.h +++ b/src/include/Str.h @@ -39,21 +39,21 @@ * is a standard library header. */ -#include "Int.h" - #include +#include +#include /** * Convert UTF-16 into a Unicode codepoint. */ -extern UInt32 StrUtf16Decode(UInt16, UInt16); +extern uint32_t StrUtf16Decode(uint16_t, uint16_t); /** * Take a Unicode codepoint and encode it into a string buffer containing * between 1 and 4 bytes. The string buffer is allocated on the heap, * so it should be freed when it is no longer needed. */ -extern char * StrUtf8Encode(UInt32); +extern char * StrUtf8Encode(uint32_t); /** * Duplicate a null-terminated string, returning a new string on the @@ -87,7 +87,7 @@ extern char * StrConcat(size_t,...); * string consists only of blank characters, as determined by * .Xr isblank 3 . */ -extern int StrBlank(const char *str); +extern bool StrBlank(const char *str); /** * Generate a string of the specified length, containing random @@ -124,6 +124,6 @@ extern char * StrLower(char *); * function returns a boolean value indicating whether or not * strcmp() returned 0. */ -extern int StrEquals(const char *, const char *); +extern bool StrEquals(const char *, const char *); #endif /* CYTOPLASM_STR_H */ diff --git a/src/include/Stream.h b/src/include/Stream.h index 7c6a1a5..a62a033 100644 --- a/src/include/Stream.h +++ b/src/include/Stream.h @@ -39,6 +39,8 @@ #include "Io.h" #include +#include +#include /** * An opaque structure analogous to C's FILE pointers. @@ -172,7 +174,7 @@ extern off_t StreamSeek(Stream *, off_t, int); * .Xr feof 3 * function. */ -extern int StreamEof(Stream *); +extern bool StreamEof(Stream *); /** * Test the stream for an error condition, returning a boolean value @@ -181,7 +183,7 @@ extern int StreamEof(Stream *); * .Xr ferror 3 * function. */ -extern int StreamError(Stream *); +extern bool StreamError(Stream *); /** * Clear the error condition associated with the given stream, allowing diff --git a/src/include/UInt64.h b/src/include/UInt64.h deleted file mode 100644 index c16fc22..0000000 --- a/src/include/UInt64.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> - * - * 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 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 CYTOPLASM_UINT64_H -#define CYTOPLASM_UINT64_H - -/*** - * @Nm UInt64 - * @Nd Fixed-width 64 bit integers. - * @Dd August 11, 2023 - * - * .Pp - * ANSI C89 (or C99 for that matter) provides no required mechanism - * for 64 bit integers. Nevertheless, many compilers provide them as - * extensions. However, since it is not a gaurantee, and to be fully - * standards-compliant and thus portable, a platform-agnostic interface - * is required. This header provides such an interface. If the platform - * has a 64 bit integer type, that is used, and native operations are - * performed by C preprocessor macro expansion. Otherwise, a - * compatibility layer is provided, which implements 64-bit - * arithmetic on an array of 2 32-bit numbers which are provided by - * .Xr Int 3 . - * .Pp - * Note that 64-bit emulation is certainly not as performant as using - * native 64-bit operations, so whenever possible, the native - * operations should be preferred. However, since C provides no required - * 64 bit integer on 32-bit and less platforms, this API can be used as - * a "good enough" fallback mechanism. - * .Pp - * Also note that this implementation, both in the native and - * non-native forms, makes some assumptions: - * .Bl -bullet -width Ds - * .It - * When a cast from a larger integer to a smaller integer is performed, - * the upper bits are truncated, not the lower bits. - * .It - * Negative numbers are represented in memory and in registers in two's - * compliment form. - * .El - * .Pp - * This API may provide unexpected output if these assumptions are - * false for a given platform. - * - * @ignore-typedefs - */ - -#include "Int.h" - -#include - -#ifndef INT64_FORCE_EMULATED - -#define BIT64_MAX 18446744073709551615UL - -#if UINT_MAX == BIT64_MAX -/* typedef signed int Int64; */ -typedef unsigned int UInt64; - -#define UINT64_NATIVE - -#elif ULONG_MAX == BIT64_MAX -/* typedef signed int Int64; */ -typedef unsigned long UInt64; - -#define UINT64_NATIVE - -#endif - -#endif /* ifndef INT64_FORCE_EMULATED */ - -#ifdef UINT64_NATIVE - -#define UInt64Create(high, low) (((UInt64) (high) << 32) | (low)) -#define UInt64Low(a) ((UInt32) ((a) & 0x00000000FFFFFFFF)) -#define UInt64High(a) ((UInt32) ((a) >> 32)) - -#define UInt64Add(a, b) ((a) + (b)) -#define UInt64Sub(a, b) ((a) - (b)) -#define UInt64Mul(a, b) ((a) * (b)) -#define UInt64Div(a, b) ((a) / (b)) -#define UInt64Rem(a, b) ((a) % (b)) - -#define UInt64Sll(a, b) ((a) << (b)) -#define UInt64Srl(a, b) ((a) >> (b)) - -#define UInt64And(a, b) ((a) & (b)) -#define UInt64Or(a, b) ((a) | (b)) -#define UInt64Xor(a, b) ((a) ^ (b)) -#define UInt64Not(a) (~(a)) - -#define UInt64Eq(a, b) ((a) == (b)) -#define UInt64Lt(a, b) ((a) < (b)) -#define UInt64Gt(a, b) ((a) > (b)) - -#define UInt64Neq(a, b) ((a) != (b)) -#define UInt64Leq(a, b) ((a) <= (b)) -#define UInt64Geq(a, b) ((a) >= (b)) - -#else - -/** - * For platforms that do not have a native integer large enough to - * store a 64 bit integer, this struct is used. i[0] contains the low - * bits of integer, and i[1] contains the high bits of the integer. - * .Pp - * This struct should not be accessed directly, because UInt64 may not - * actually be this struct, it might be an actual integer type. For - * maximum portability, only use the functions defined here to - * manipulate 64 bit integers. - */ -typedef struct -{ - UInt32 i[2]; -} UInt64; - -/** - * Create a new unsigned 64 bit integer using the given high and low - * bits. - */ -extern UInt64 UInt64Create(UInt32, UInt32); - -/** - * Add two unsigned 64 bit integers together. - */ -extern UInt64 UInt64Add(UInt64, UInt64); - -/** - * Subtract the second 64 bit integer from the first. - */ -extern UInt64 UInt64Sub(UInt64, UInt64); - -/** - * Multiply two 64 bit integers together. The non-native version of - * this function uses the Russian Peasant method of multiplication, - * which should afford more performance than a naive multiplication by - * addition, but it is still rather slow and depends on the size of - * the integers being multiplied. - */ -extern UInt64 UInt64Mul(UInt64, UInt64); - -/** - * Divide the first 64 bit integer by the second and return the - * quotient. The non-native version of this function uses naive binary - * long division, which is slow, but gauranteed to finish in constant - * time. - */ -extern UInt64 UInt64Div(UInt64, UInt64); - -/** - * Divide the first 64 bit integer by the second and return the - * remainder. The non-native version of this function uses naive binary - * long division, which is slow, but gauranteed to finish in constant - * time. - */ -extern UInt64 UInt64Rem(UInt64, UInt64); - -/** - * Perform a left logical bit shift of a 64 bit integer. The second - * parameter is how many places to shift, and is declared as a regular - * integer because anything more than 64 does not make sense. - */ -extern UInt64 UInt64Sll(UInt64, int); - -/** - * Perform a right logical bit shift of a 64 bit integer. The second - * parameter is how many places to shift, and is declared as a regular - * integer because anything more than 64 does not make sense. - */ -extern UInt64 UInt64Srl(UInt64, int); - -/** - * Perform a bitwise AND (&) of the provided 64 bit integers. - */ -extern UInt64 UInt64And(UInt64, UInt64); - -/** - * Perform a bitwise OR (|) of the provided 64 bit integers. - */ -extern UInt64 UInt64Or(UInt64, UInt64); - -/** - * Perform a bitwise XOR (^) of the provided 64 bit integers. - */ -extern UInt64 UInt64Xor(UInt64, UInt64); - -/** - * Perform a bitwise NOT (~) of the provided 64 bit integer. - */ -extern UInt64 UInt64Not(UInt64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if they are equal. - */ -extern int UInt64Eq(UInt64, UInt64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if the second operand is strictly - * less than the first. - */ -extern int UInt64Lt(UInt64, UInt64); - -/** - * Perform a comparison of the provided 64 bit integers and return a C - * boolean that is true if and only if the second operand is strictly - * greater than the first. - */ -extern int UInt64Gt(UInt64, UInt64); - -#define UInt64Low(a) ((a).i[0]) -#define UInt64High(a) ((a).i[1]) - -#define UInt64Neq(a, b) (!UInt64Eq(a, b)) -#define UInt64Leq(a, b) (UInt64Eq(a, b) || UInt64Lt(a, b)) -#define UInt64Geq(a, b) (UInt64Eq(a, b) || UInt64Gt(a, b)) - -#endif - -#define UINT64_STRBUF 65 /* Base 2 representation with '\0' */ - -/** - * Convert a 64 bit integer to a string in an arbitrary base - * representation specified by the second parameter, using the provided - * buffer and length specified by the third and fourth parameters. To - * guarantee that the string will fit in the buffer, allocate it of - * size UINT64_STRBUF or larger. Note that a buffer size smaller than - * UINT64_STRBUF will invoke undefined behavior. - */ -extern size_t UInt64Str(UInt64, int, char *, size_t); - -#endif /* CYTOPLASM_UINT64_H */ diff --git a/src/include/Util.h b/src/include/Util.h index e7bef57..feafcff 100644 --- a/src/include/Util.h +++ b/src/include/Util.h @@ -43,7 +43,6 @@ #include #include "Stream.h" -#include "UInt64.h" /** * Get the current timestamp in milliseconds since the Unix epoch. This @@ -61,7 +60,7 @@ * overflow before it even gets to this function, which will cause this * function to produce unexpected results. */ -extern UInt64 UtilServerTs(void); +extern uint64_t UtilTsMillis(void); /** * Use @@ -70,7 +69,7 @@ extern UInt64 UtilServerTs(void); * was an error getting the last modified time of a file. This is * primarily useful for caching file data. */ -extern UInt64 UtilLastModified(char *); +extern uint64_t UtilLastModified(char *); /** * This function behaves just like the system call @@ -86,7 +85,7 @@ extern int UtilMkdir(const char *, const mode_t); * .Xr nanosleep 2 * to make its usage much, much simpler. */ -extern int UtilSleepMillis(UInt64); +extern int UtilSleepMillis(uint64_t); /** * This function works identically to the POSIX @@ -112,6 +111,6 @@ extern ssize_t UtilGetLine(char **, size_t *, Stream *); * .Fn pthread_self * to a number. */ -extern UInt32 UtilThreadNo(void); +extern uint32_t UtilThreadNo(void); #endif /* CYTOPLASM_UTIL_H */ From c3429f035cb275dc3d43cc1a100ac3eda77742f8 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 17:18:17 -0500 Subject: [PATCH 27/37] Update CHANGELOG.md --- CHANGELOG.md | 61 +++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71cfee1..e3edab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,30 +1,33 @@ -# Cytoplasm Change Log - -This document contains the complete change log for every official release of -Cytoplasm. It is intended to be updated with every commit that makes a user-facing -change worth reporting in the change log. As such, it changes frequently between -releases. Final change log entries are published as [Releases](releases). - -## v0.4.1 - -### New Features - -- Added an option to `j2s` to allow additional fields in structures and ignore them in -encoding and decoding. Note that additional fields are totally untouched—they -are not even initialized to a default value. -- Fixed a memory leak that would occur in code generated by `j2s` under - specific circumstances. -- Added `JsonMerge()` to the JSON API to merge two JSON objects together. -- Make `HttpRouter` decode path parts before matching them on regular expressions. - -## v0.4.0 - -**Released on November 1, 2023** - -This is the first independent release of Cytoplasm! Last month, Cytoplasm was -split off of [Telodendria](/Telodendria/Telodendria) to become its own independent -project with its own independent releases. This allows it to develop at a much more -rapid pace than Telodendria. - -Changes in future releases will be reported here. Since this is the first release, +# Cytoplasm Change Log + +This document contains the complete change log for every official release of +Cytoplasm. It is intended to be updated with every commit that makes a user-facing +change worth reporting in the change log. As such, it changes frequently between +releases. Final change log entries are published as [Releases](releases). + +## v0.4.1 + +Cytoplasm is now a C99 library! Upgrading from C89 to C99 makes Cytoplasm more portable +than ever. + +### New Features + +- Added an option to `j2s` to allow additional fields in structures and ignore them in +encoding and decoding. Note that additional fields are totally untouched—they +are not even initialized to a default value. +- Fixed a memory leak that would occur in code generated by `j2s` under + specific circumstances. +- Added `JsonMerge()` to the JSON API to merge two JSON objects together. +- Make `HttpRouter` decode path parts before matching them on regular expressions. + +## v0.4.0 + +**Released on November 1, 2023** + +This is the first independent release of Cytoplasm! Last month, Cytoplasm was +split off of [Telodendria](/Telodendria/Telodendria) to become its own independent +project with its own independent releases. This allows it to develop at a much more +rapid pace than Telodendria. + +Changes in future releases will be reported here. Since this is the first release, there are no changes to show. \ No newline at end of file From 08166dd3a77609b7a87e618f42099bbfd346204c Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 17:26:17 -0500 Subject: [PATCH 28/37] Don't use `install` because it is not POSIX. Closes #13. --- configure | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/configure b/configure index f962059..e3f6f5b 100755 --- a/configure +++ b/configure @@ -184,22 +184,28 @@ compile_doc() { install_out() { src="$1" out="$2" + dir=$(dirname "$out") - echo "${TAB}install -D \"$src\" \"$out\"" + echo "${TAB}mkdir -p \"$dir\"" + echo "${TAB}cp \"$src\" \"$out\"" } install_man() { src="${OUT}/man/man3/${LIB_NAME}-$(basename $1 .h).3" out="$2" + dir=$(dirname "$out") - echo "${TAB}install -D \"$src\" \"$out\"" + echo "${TAB}mkdir -p \"$dir\"" + echo "${TAB}cp \"$src\" \"$out\"" } install_tool() { src=${OUT}/bin/$(basename "$1" .c) out="$2" + dir=$(dirname "$out") - echo "${TAB}install -D \"$src\" \"$out\"" + echo "${TAB}mkdir -p \"$dir\"" + echo "${TAB}cp \"$src\" \"$out\"" } uninstall_out() { From 11e0a34c02a7c8e402b61d3014ec7b05d9319462 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 17:49:36 -0500 Subject: [PATCH 29/37] Update README.md --- README.md | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index d173524..08a8b5d 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -

+

Cytoplasm (libcytoplasm)

-Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications. It allows applications to take advantage of the speed, flexibility, and simplicity of the C programming language, while providing helpful code to allow applications to perform various complex tasks with minimal effort. Cytoplasm provides high-level data structures, a basic logging facility, an HTTP client and server, and more. It also reports memory leaks, which can aid in debugging. +Cytoplasm is a general-purpose C library for creating high-level (particularly networked and multi-threaded) C applications. It allows applications to take advantage of the speed, flexibility, and simplicity of the C programming language, while providing helpful code to allow applications to perform various complex tasks with minimal effort. Cytoplasm provides high-level data structures, a basic logging facility, an HTTP client and server, and more. It also reports memory leaks, which can aid in debugging, particularly on systems that don't have advanced tools like `valgrind`. -Cytoplasm aims not to only do one thing well, but to do many things good enough. This is in contrast to other libraries, which only do one thing and thus require the developer to pull in many different libraries. The primary target of Cytoplasm is simple yet higher level C applications that have to perform relatively complex tasks, but don't want to depend on a large number of dependencies. +Cytoplasm aims not to only do one thing well, but to do many things good enough. This is in contrast to other libraries, which only do one thing and thus require the developer to pull in many different libraries for a broad range of functionality. The primary target of Cytoplasm is simple yet higher level C applications that have to perform relatively complex tasks, but don't want to depend on a large number of dependencies. -Cytoplasm is extremely opinionated on the way programs using it are written. It strives to create a comprehensive and tightly-integrated programming environment, while also maintaining C programming correctness. It doesn't do any macro magic or make C look like anything other than C. It is written entirely in C89, and depends only on a POSIX environment. This differentiates it from other general-purpose libraries that often require modern compilers and non-standard language and environment features. Cytoplasm is intended to be extremely portable and simple, while still providing some of the functionality expected in higher-level programming languages in a platform-agnostic manner. In the case of TLS, Cytoplasm wraps low-level TLS libraries to offer a single, unified interface to TLS so that programs do not have to care about the underlying implementation. +Cytoplasm is extremely opinionated on the way programs using it are written. It strives to create a comprehensive and tightly-integrated programming environment, while also maintaining C programming correctness. It doesn't do any macro magic or make C look like anything other than C. It is written entirely in C99, and depends only on a POSIX environment. This differentiates it from other general-purpose libraries that often require more modern compilers and non-standard language and environment features. Cytoplasm is intended to be extremely portable and simple, while still providing some of the functionality expected in higher-level programming languages in a platform-agnostic manner. In the case of TLS, Cytoplasm wraps low-level TLS libraries to offer a single, unified interface to TLS so that programs do not have to care about the underlying implementation. Cytoplasm is probably not suitable for embedded programming. It makes liberal use of the heap, and while data structures are designed to conserve memory where possible and practical, minimal memory usage is not really a design goal for Cytoplasm, although Cytoplasm takes care not to use any more memory than it absolutely needs. Cytoplasm also wraps a few standard libraries with additional logic and checking. While this ensures better runtime safety, this inevitably adds a little overhead, which may be unsuitable for time- or space-critical tasks. -Originally a part of Telodendria (https://telodendria.io), a Matrix homeserver written in C, Cytoplasm was split off into its own project due to the desire of some Telodendria developers to use Telodendria's code in other projects. Cytoplasm is still an official Telodendria project, but it is designed specifically to be distributed and used totally independent of Telodendria. +Originally a part of Telodendria ([Website](https://telodendria.io), [Repo](/Telodendria/Telodendria)), a Matrix homeserver written in C, Cytoplasm was split off into its own project due to the desire of some Telodendria developers to use Telodendria's code in other projects. Cytoplasm is still an official Telodendria project, but it is designed specifically to be distributed and used totally independent of Telodendria. The name "Cytoplasm" was chosen for a few reasons. It plays off the precedent set up by the Matrix organization in naming projects after the parts of a neuron. It also speaks to the function of Cytoplasm. The cytoplasm of a cell is the supporting material. It is what gives the cell its shape, and it facilitates the movement of materials to the other cell parts. Likewise, Cytoplasm aims to provide a support mechanism for C applications that have to perform complex tasks beyond what the C standard library provides. @@ -17,14 +17,7 @@ Cytoplasm also starts with a C, which I think is a nice touch for C libraries. I ## Requirements -Cytoplasm makes the following assumptions about the underlying hardware: - -- It has words sizes that are powers of 2, and a native 32-bit integer type exists. -- Integers are represented using two's compliment for negatives. - -The ANSI C standard requires an integer type of at least 32 bits, but does not require any more. If Cytoplasm is built on 32-bit platforms that don't provide a native 64-bit integer type, Cytoplasm emulates 64-bit integers. This can make it more portable. - -Cytoplasm aims to have zero software dependencies beyond what is mandated by POSIX. You only need the standard math and pthread libraries to build it. TLS support can optionally be enabled with the configuration script. The supported TLS implementations are as follows: +Cytoplasm aims to have zero software dependencies beyond what is mandated by POSIX. You only need a standard C99 compiler, and the standard `math` and `pthread` libraries to build Cytoplasm. TLS support can optionally be enabled with the configuration script. The supported TLS implementations are as follows: - OpenSSL - LibreSSL @@ -60,14 +53,11 @@ The `configure` script has a number of optional flags, which are as follows: - `--with-(openssl|libressl)`: Select the TLS implementation to use. OpenSSL is selected by default. - `--disable-tls`: Disable TLS altogether. - `--prefix=`: Set the install prefix to set by default in the `Makefile`. This defaults to `/usr/local`, which should be appropriate for most Unix-like systems. -- `--(enable|disable)-ld-extra`: Control whether or not to enable additional linking flags that create a more optimized binary. For large compilers such as GCC and Clang, these flags should be enabled. However, if you are using a small or more obscure compiler, then these flags may not be supported, so you can disable them with this option. - `--(enable|disable)-debug`: Control whether or not to enable debug mode. This sets the optimization level to 0 and builds with debug symbols. Useful for running with a debugger. -- `--static` and `--no-static`: Controls whether static binaries for tools are built by default. On BSD systems, `--static` is perfectly acceptable, but on GNU systems, `--no-static` is often desirable to silence warnings about static binaries emitted by the GNU linker. Cytoplasm can be customized with the following options: - `--lib-name=`: The output name of the library. This defaults to `Cytoplasm` and should in most cases not be changed. -- `--lib-version=`: The version string to embed in the library binaries. This can be used to indicate build customizations or non-release versions of Cytoplasm. The following recipes are available in the generated `Makefile`: @@ -96,13 +86,13 @@ Cytoplasm provides the typical .so and .a files, which can be used to link progr Here is the canonical Hello World written with Cytoplasm: ```c - #include +#include - int Main(void) - { - Log(LOG_INFO, "Hello World!"); - return 0; - } +int Main(void) +{ + Log(LOG_INFO, "Hello World!"); + return 0; +} ``` If this file is `Hello.c`, then you can compile it by doing this: From 31c9bc7f1c996946b0dd3268c675eaba29846935 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 17:56:58 -0500 Subject: [PATCH 30/37] Update Cytoplasm license text for 2024. --- LICENSE.txt | 2 +- examples/PrintArgsAndEnv.c | 2 +- src/Args.c | 2 +- src/Array.c | 2 +- src/Base64.c | 2 +- src/Cron.c | 2 +- src/Cytoplasm.c | 2 +- src/Db.c | 2 +- src/Graph.c | 2 +- src/HashMap.c | 2 +- src/HeaderParser.c | 2 +- src/Http.c | 2 +- src/HttpClient.c | 2 +- src/HttpRouter.c | 2 +- src/HttpServer.c | 2 +- src/Io.c | 2 +- src/Io/IoFd.c | 2 +- src/Io/IoFile.c | 2 +- src/Json.c | 2 +- src/Log.c | 2 +- src/Memory.c | 2 +- src/Queue.c | 2 +- src/Rand.c | 2 +- src/RtStub.c | 2 +- src/Runtime.c | 2 +- src/Sha.c | 2 +- src/Sha/Sha1.c | 2 +- src/Sha/Sha256.c | 2 +- src/Str.c | 2 +- src/Stream.c | 2 +- src/Tls.c | 2 +- src/Tls/TlsLibreSSL.c | 2 +- src/Tls/TlsOpenSSL.c | 2 +- src/Uri.c | 2 +- src/Util.c | 2 +- src/include/Args.h | 2 +- src/include/Array.h | 2 +- src/include/Base64.h | 2 +- src/include/Cron.h | 2 +- src/include/Cytoplasm.h | 2 +- src/include/Db.h | 2 +- src/include/Graph.h | 2 +- src/include/HashMap.h | 2 +- src/include/HeaderParser.h | 2 +- src/include/Http.h | 2 +- src/include/HttpClient.h | 2 +- src/include/HttpRouter.h | 2 +- src/include/HttpServer.h | 2 +- src/include/Io.h | 2 +- src/include/Json.h | 2 +- src/include/Log.h | 2 +- src/include/Memory.h | 2 +- src/include/Queue.h | 2 +- src/include/Rand.h | 2 +- src/include/Runtime.h | 2 +- src/include/Sha.h | 2 +- src/include/Str.h | 2 +- src/include/Stream.h | 2 +- src/include/Tls.h | 2 +- src/include/Uri.h | 2 +- src/include/Util.h | 2 +- tools/hdoc.c | 2 +- tools/http.c | 2 +- tools/j2s.c | 2 +- tools/tp.c | 2 +- 65 files changed, 65 insertions(+), 65 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index 90f6e6d..65961c2 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/examples/PrintArgsAndEnv.c b/examples/PrintArgsAndEnv.c index 1b58108..ce3f74a 100644 --- a/examples/PrintArgsAndEnv.c +++ b/examples/PrintArgsAndEnv.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Args.c b/src/Args.c index c9f3000..d25077f 100644 --- a/src/Args.c +++ b/src/Args.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Array.c b/src/Array.c index d16db3f..c2af556 100644 --- a/src/Array.c +++ b/src/Array.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Base64.c b/src/Base64.c index ec81935..13c117b 100644 --- a/src/Base64.c +++ b/src/Base64.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Cron.c b/src/Cron.c index dd820ba..396d36b 100644 --- a/src/Cron.c +++ b/src/Cron.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Cytoplasm.c b/src/Cytoplasm.c index 8c435c4..d3e2d0b 100644 --- a/src/Cytoplasm.c +++ b/src/Cytoplasm.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Db.c b/src/Db.c index 4d2983a..22456ac 100644 --- a/src/Db.c +++ b/src/Db.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Graph.c b/src/Graph.c index a4d63ed..8e583d1 100644 --- a/src/Graph.c +++ b/src/Graph.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/HashMap.c b/src/HashMap.c index d158b3f..32a3199 100644 --- a/src/HashMap.c +++ b/src/HashMap.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/HeaderParser.c b/src/HeaderParser.c index e08af75..1915dc6 100644 --- a/src/HeaderParser.c +++ b/src/HeaderParser.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Http.c b/src/Http.c index cab1220..3572c66 100644 --- a/src/Http.c +++ b/src/Http.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/HttpClient.c b/src/HttpClient.c index 88d7179..3d9f075 100644 --- a/src/HttpClient.c +++ b/src/HttpClient.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/HttpRouter.c b/src/HttpRouter.c index 7777fcd..20070af 100644 --- a/src/HttpRouter.c +++ b/src/HttpRouter.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/HttpServer.c b/src/HttpServer.c index b2a9535..8ed5a66 100644 --- a/src/HttpServer.c +++ b/src/HttpServer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Io.c b/src/Io.c index 54d250c..3e30444 100644 --- a/src/Io.c +++ b/src/Io.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Io/IoFd.c b/src/Io/IoFd.c index eaa1539..5abad5e 100644 --- a/src/Io/IoFd.c +++ b/src/Io/IoFd.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Io/IoFile.c b/src/Io/IoFile.c index cdd40ab..d55686a 100644 --- a/src/Io/IoFile.c +++ b/src/Io/IoFile.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Json.c b/src/Json.c index 3ff9880..872c266 100644 --- a/src/Json.c +++ b/src/Json.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Log.c b/src/Log.c index d5a5799..ada86a4 100644 --- a/src/Log.c +++ b/src/Log.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Memory.c b/src/Memory.c index 134505c..4083143 100644 --- a/src/Memory.c +++ b/src/Memory.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Queue.c b/src/Queue.c index db228d1..11e1ad5 100644 --- a/src/Queue.c +++ b/src/Queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Rand.c b/src/Rand.c index 3ece67a..f9cf6fc 100644 --- a/src/Rand.c +++ b/src/Rand.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/RtStub.c b/src/RtStub.c index dd0ed12..a09527f 100644 --- a/src/RtStub.c +++ b/src/RtStub.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Runtime.c b/src/Runtime.c index 9a69875..56d8e4d 100644 --- a/src/Runtime.c +++ b/src/Runtime.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Sha.c b/src/Sha.c index 1cfe502..377ae14 100644 --- a/src/Sha.c +++ b/src/Sha.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Sha/Sha1.c b/src/Sha/Sha1.c index edd250f..9e12d56 100644 --- a/src/Sha/Sha1.c +++ b/src/Sha/Sha1.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Sha/Sha256.c b/src/Sha/Sha256.c index 82ea046..2563246 100644 --- a/src/Sha/Sha256.c +++ b/src/Sha/Sha256.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Str.c b/src/Str.c index bcbb63d..fa8391c 100644 --- a/src/Str.c +++ b/src/Str.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Stream.c b/src/Stream.c index 539ec20..63bc3d5 100644 --- a/src/Stream.c +++ b/src/Stream.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Tls.c b/src/Tls.c index d3ad08f..659cba6 100644 --- a/src/Tls.c +++ b/src/Tls.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Tls/TlsLibreSSL.c b/src/Tls/TlsLibreSSL.c index 27b9fa7..dc09b11 100644 --- a/src/Tls/TlsLibreSSL.c +++ b/src/Tls/TlsLibreSSL.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Tls/TlsOpenSSL.c b/src/Tls/TlsOpenSSL.c index cd6a635..c056ebc 100644 --- a/src/Tls/TlsOpenSSL.c +++ b/src/Tls/TlsOpenSSL.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Uri.c b/src/Uri.c index ca1ad96..1e88a7d 100644 --- a/src/Uri.c +++ b/src/Uri.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/Util.c b/src/Util.c index 6701eb7..962ff0b 100644 --- a/src/Util.c +++ b/src/Util.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Args.h b/src/include/Args.h index 2161c1b..f6d0dff 100644 --- a/src/include/Args.h +++ b/src/include/Args.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Array.h b/src/include/Array.h index 0705b2b..65affeb 100644 --- a/src/include/Array.h +++ b/src/include/Array.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Base64.h b/src/include/Base64.h index 74c8956..2279a1b 100644 --- a/src/include/Base64.h +++ b/src/include/Base64.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Cron.h b/src/include/Cron.h index 00280cc..0963395 100644 --- a/src/include/Cron.h +++ b/src/include/Cron.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Cytoplasm.h b/src/include/Cytoplasm.h index 97a4a54..0119e06 100644 --- a/src/include/Cytoplasm.h +++ b/src/include/Cytoplasm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Db.h b/src/include/Db.h index 9aa0758..f4c41d2 100644 --- a/src/include/Db.h +++ b/src/include/Db.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Graph.h b/src/include/Graph.h index 02e4e02..f9a4c55 100644 --- a/src/include/Graph.h +++ b/src/include/Graph.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/HashMap.h b/src/include/HashMap.h index 716dacc..a808494 100644 --- a/src/include/HashMap.h +++ b/src/include/HashMap.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/HeaderParser.h b/src/include/HeaderParser.h index 52d8e33..5959c68 100644 --- a/src/include/HeaderParser.h +++ b/src/include/HeaderParser.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Http.h b/src/include/Http.h index 37875d8..fb50169 100644 --- a/src/include/Http.h +++ b/src/include/Http.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/HttpClient.h b/src/include/HttpClient.h index 28fe3c2..ea151b4 100644 --- a/src/include/HttpClient.h +++ b/src/include/HttpClient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/HttpRouter.h b/src/include/HttpRouter.h index 2df3db7..130f2a4 100644 --- a/src/include/HttpRouter.h +++ b/src/include/HttpRouter.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/HttpServer.h b/src/include/HttpServer.h index c539ac7..ee09064 100644 --- a/src/include/HttpServer.h +++ b/src/include/HttpServer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Io.h b/src/include/Io.h index 06afb77..09c400f 100644 --- a/src/include/Io.h +++ b/src/include/Io.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Json.h b/src/include/Json.h index e74c77d..261aced 100644 --- a/src/include/Json.h +++ b/src/include/Json.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Log.h b/src/include/Log.h index 1567b6e..0074dae 100644 --- a/src/include/Log.h +++ b/src/include/Log.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Memory.h b/src/include/Memory.h index d6836ee..80c37d8 100644 --- a/src/include/Memory.h +++ b/src/include/Memory.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Queue.h b/src/include/Queue.h index 1c148b7..60a03f3 100644 --- a/src/include/Queue.h +++ b/src/include/Queue.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Rand.h b/src/include/Rand.h index 69fdb7f..cb7713e 100644 --- a/src/include/Rand.h +++ b/src/include/Rand.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Runtime.h b/src/include/Runtime.h index f23a1ba..c486e04 100644 --- a/src/include/Runtime.h +++ b/src/include/Runtime.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Sha.h b/src/include/Sha.h index 25b6247..a23ef35 100644 --- a/src/include/Sha.h +++ b/src/include/Sha.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Str.h b/src/include/Str.h index 87bc92b..35842e8 100644 --- a/src/include/Str.h +++ b/src/include/Str.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Stream.h b/src/include/Stream.h index a62a033..1bb30bb 100644 --- a/src/include/Stream.h +++ b/src/include/Stream.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Tls.h b/src/include/Tls.h index 8314f7d..047ffbd 100644 --- a/src/include/Tls.h +++ b/src/include/Tls.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Uri.h b/src/include/Uri.h index a47bf28..7c55d75 100644 --- a/src/include/Uri.h +++ b/src/include/Uri.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/src/include/Util.h b/src/include/Util.h index feafcff..4e2db90 100644 --- a/src/include/Util.h +++ b/src/include/Util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/tools/hdoc.c b/tools/hdoc.c index 1d1bbaa..e905c0c 100644 --- a/tools/hdoc.c +++ b/tools/hdoc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/tools/http.c b/tools/http.c index 0b32b74..a2b97bb 100644 --- a/tools/http.c +++ b/tools/http.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/tools/j2s.c b/tools/j2s.c index 57a8b6e..dc33c9a 100644 --- a/tools/j2s.c +++ b/tools/j2s.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files diff --git a/tools/tp.c b/tools/tp.c index 3be903e..f178948 100644 --- a/tools/tp.c +++ b/tools/tp.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net> + * Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation files From c489eff517a68ad30b56d7d63ab82b80692f9347 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 18:11:44 -0500 Subject: [PATCH 31/37] Set -Wextra on fancy compilers. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index e3f6f5b..abe4636 100755 --- a/configure +++ b/configure @@ -63,7 +63,7 @@ for arg in $SCRIPT_ARGS; do gcc*|clang*) # "Fancy" compilers that support a plethora of additional flags we # want to enable if present. - CFLAGS="-Wall -Werror -pedantic -std=c99 ${CFLAGS}" + CFLAGS="-Wall -Wextra -Werror -pedantic -std=c99 ${CFLAGS}" LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections" ;; esac From cd7df7bbb4eb470a654e6327f1e215fc4430fe9e Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 18:22:37 -0500 Subject: [PATCH 32/37] Enable higher optimization on fancy compilers. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index abe4636..25dba3a 100755 --- a/configure +++ b/configure @@ -63,7 +63,7 @@ for arg in $SCRIPT_ARGS; do gcc*|clang*) # "Fancy" compilers that support a plethora of additional flags we # want to enable if present. - CFLAGS="-Wall -Wextra -Werror -pedantic -std=c99 ${CFLAGS}" + CFLAGS="-Wall -Wextra -Werror -pedantic -std=c99 -O3 ${CFLAGS}" LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections" ;; esac From 461357b5261599eca59dcc7bb22d7e5efaf550ba Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 18:40:31 -0500 Subject: [PATCH 33/37] Move headers from `src/include` to `include/Cytoplasm`. This makes it easier to build Cytoplasm as a component of another program (for example, Telodendria), or as a standalone system library. --- configure | 2 +- {src/include => include/Cytoplasm}/Args.h | 0 {src/include => include/Cytoplasm}/Array.h | 0 {src/include => include/Cytoplasm}/Base64.h | 0 {src/include => include/Cytoplasm}/Cron.h | 0 {src/include => include/Cytoplasm}/Cytoplasm.h | 0 {src/include => include/Cytoplasm}/Db.h | 0 {src/include => include/Cytoplasm}/Graph.h | 0 {src/include => include/Cytoplasm}/HashMap.h | 0 {src/include => include/Cytoplasm}/HeaderParser.h | 0 {src/include => include/Cytoplasm}/Http.h | 0 {src/include => include/Cytoplasm}/HttpClient.h | 0 {src/include => include/Cytoplasm}/HttpRouter.h | 0 {src/include => include/Cytoplasm}/HttpServer.h | 0 {src/include => include/Cytoplasm}/Io.h | 0 {src/include => include/Cytoplasm}/Json.h | 0 {src/include => include/Cytoplasm}/Log.h | 0 {src/include => include/Cytoplasm}/Memory.h | 0 {src/include => include/Cytoplasm}/Queue.h | 0 {src/include => include/Cytoplasm}/Rand.h | 0 {src/include => include/Cytoplasm}/Runtime.h | 0 {src/include => include/Cytoplasm}/Sha.h | 0 {src/include => include/Cytoplasm}/Str.h | 0 {src/include => include/Cytoplasm}/Stream.h | 0 {src/include => include/Cytoplasm}/Tls.h | 0 {src/include => include/Cytoplasm}/Uri.h | 0 {src/include => include/Cytoplasm}/Util.h | 0 27 files changed, 1 insertion(+), 1 deletion(-) rename {src/include => include/Cytoplasm}/Args.h (100%) rename {src/include => include/Cytoplasm}/Array.h (100%) rename {src/include => include/Cytoplasm}/Base64.h (100%) rename {src/include => include/Cytoplasm}/Cron.h (100%) rename {src/include => include/Cytoplasm}/Cytoplasm.h (100%) rename {src/include => include/Cytoplasm}/Db.h (100%) rename {src/include => include/Cytoplasm}/Graph.h (100%) rename {src/include => include/Cytoplasm}/HashMap.h (100%) rename {src/include => include/Cytoplasm}/HeaderParser.h (100%) rename {src/include => include/Cytoplasm}/Http.h (100%) rename {src/include => include/Cytoplasm}/HttpClient.h (100%) rename {src/include => include/Cytoplasm}/HttpRouter.h (100%) rename {src/include => include/Cytoplasm}/HttpServer.h (100%) rename {src/include => include/Cytoplasm}/Io.h (100%) rename {src/include => include/Cytoplasm}/Json.h (100%) rename {src/include => include/Cytoplasm}/Log.h (100%) rename {src/include => include/Cytoplasm}/Memory.h (100%) rename {src/include => include/Cytoplasm}/Queue.h (100%) rename {src/include => include/Cytoplasm}/Rand.h (100%) rename {src/include => include/Cytoplasm}/Runtime.h (100%) rename {src/include => include/Cytoplasm}/Sha.h (100%) rename {src/include => include/Cytoplasm}/Str.h (100%) rename {src/include => include/Cytoplasm}/Stream.h (100%) rename {src/include => include/Cytoplasm}/Tls.h (100%) rename {src/include => include/Cytoplasm}/Uri.h (100%) rename {src/include => include/Cytoplasm}/Util.h (100%) diff --git a/configure b/configure index 25dba3a..1afdd91 100755 --- a/configure +++ b/configure @@ -10,7 +10,7 @@ echo "-------------------" BUILD="build" OUT="out" SRC="src" -INCLUDE="src/include" +INCLUDE="include/Cytoplasm" TOOLS="tools" # Default compiler flags. These must be supported by all POSIX C compilers. diff --git a/src/include/Args.h b/include/Cytoplasm/Args.h similarity index 100% rename from src/include/Args.h rename to include/Cytoplasm/Args.h diff --git a/src/include/Array.h b/include/Cytoplasm/Array.h similarity index 100% rename from src/include/Array.h rename to include/Cytoplasm/Array.h diff --git a/src/include/Base64.h b/include/Cytoplasm/Base64.h similarity index 100% rename from src/include/Base64.h rename to include/Cytoplasm/Base64.h diff --git a/src/include/Cron.h b/include/Cytoplasm/Cron.h similarity index 100% rename from src/include/Cron.h rename to include/Cytoplasm/Cron.h diff --git a/src/include/Cytoplasm.h b/include/Cytoplasm/Cytoplasm.h similarity index 100% rename from src/include/Cytoplasm.h rename to include/Cytoplasm/Cytoplasm.h diff --git a/src/include/Db.h b/include/Cytoplasm/Db.h similarity index 100% rename from src/include/Db.h rename to include/Cytoplasm/Db.h diff --git a/src/include/Graph.h b/include/Cytoplasm/Graph.h similarity index 100% rename from src/include/Graph.h rename to include/Cytoplasm/Graph.h diff --git a/src/include/HashMap.h b/include/Cytoplasm/HashMap.h similarity index 100% rename from src/include/HashMap.h rename to include/Cytoplasm/HashMap.h diff --git a/src/include/HeaderParser.h b/include/Cytoplasm/HeaderParser.h similarity index 100% rename from src/include/HeaderParser.h rename to include/Cytoplasm/HeaderParser.h diff --git a/src/include/Http.h b/include/Cytoplasm/Http.h similarity index 100% rename from src/include/Http.h rename to include/Cytoplasm/Http.h diff --git a/src/include/HttpClient.h b/include/Cytoplasm/HttpClient.h similarity index 100% rename from src/include/HttpClient.h rename to include/Cytoplasm/HttpClient.h diff --git a/src/include/HttpRouter.h b/include/Cytoplasm/HttpRouter.h similarity index 100% rename from src/include/HttpRouter.h rename to include/Cytoplasm/HttpRouter.h diff --git a/src/include/HttpServer.h b/include/Cytoplasm/HttpServer.h similarity index 100% rename from src/include/HttpServer.h rename to include/Cytoplasm/HttpServer.h diff --git a/src/include/Io.h b/include/Cytoplasm/Io.h similarity index 100% rename from src/include/Io.h rename to include/Cytoplasm/Io.h diff --git a/src/include/Json.h b/include/Cytoplasm/Json.h similarity index 100% rename from src/include/Json.h rename to include/Cytoplasm/Json.h diff --git a/src/include/Log.h b/include/Cytoplasm/Log.h similarity index 100% rename from src/include/Log.h rename to include/Cytoplasm/Log.h diff --git a/src/include/Memory.h b/include/Cytoplasm/Memory.h similarity index 100% rename from src/include/Memory.h rename to include/Cytoplasm/Memory.h diff --git a/src/include/Queue.h b/include/Cytoplasm/Queue.h similarity index 100% rename from src/include/Queue.h rename to include/Cytoplasm/Queue.h diff --git a/src/include/Rand.h b/include/Cytoplasm/Rand.h similarity index 100% rename from src/include/Rand.h rename to include/Cytoplasm/Rand.h diff --git a/src/include/Runtime.h b/include/Cytoplasm/Runtime.h similarity index 100% rename from src/include/Runtime.h rename to include/Cytoplasm/Runtime.h diff --git a/src/include/Sha.h b/include/Cytoplasm/Sha.h similarity index 100% rename from src/include/Sha.h rename to include/Cytoplasm/Sha.h diff --git a/src/include/Str.h b/include/Cytoplasm/Str.h similarity index 100% rename from src/include/Str.h rename to include/Cytoplasm/Str.h diff --git a/src/include/Stream.h b/include/Cytoplasm/Stream.h similarity index 100% rename from src/include/Stream.h rename to include/Cytoplasm/Stream.h diff --git a/src/include/Tls.h b/include/Cytoplasm/Tls.h similarity index 100% rename from src/include/Tls.h rename to include/Cytoplasm/Tls.h diff --git a/src/include/Uri.h b/include/Cytoplasm/Uri.h similarity index 100% rename from src/include/Uri.h rename to include/Cytoplasm/Uri.h diff --git a/src/include/Util.h b/include/Cytoplasm/Util.h similarity index 100% rename from src/include/Util.h rename to include/Cytoplasm/Util.h From 5d87da31cda74e6808eebca72e9475aabde86532 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 13 Jan 2024 18:55:31 -0500 Subject: [PATCH 34/37] j2s generated code is now C99. It also no longer requires on the now-defunct Int64.h. --- tools/j2s.c | 61 ++++++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/tools/j2s.c b/tools/j2s.c index dc33c9a..1ef0660 100644 --- a/tools/j2s.c +++ b/tools/j2s.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -323,7 +324,7 @@ Main(Array * args) while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal)) { char *fieldType; - int isArrType = 0; + bool isArrType = false; JsonValue *requiredVal; JsonValue *ignoreVal; @@ -346,7 +347,7 @@ Main(Array * args) { fieldType++; fieldType[strlen(fieldType) - 1] = '\0'; - isArrType = 1; + isArrType = true; } if (!StrEquals(fieldType, "object") && @@ -459,9 +460,11 @@ Main(Array * args) StreamPrintf(headerFile, "#ifndef %s\n", guard); StreamPrintf(headerFile, "#define %s\n\n", guard); + StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); + StreamPrintf(headerFile, "#include \n"); StreamPrintf(headerFile, "#include \n"); - StreamPrintf(headerFile, "#include \n"); StreamPutc(headerFile, '\n'); @@ -516,11 +519,11 @@ Main(Array * args) } else if (StrEquals(fieldType, "integer")) { - cType = "Int64"; + cType = "int64_t"; } else if (StrEquals(fieldType, "boolean")) { - cType = "int"; + cType = "bool"; } else if (StrEquals(fieldType, "float")) { @@ -622,8 +625,8 @@ Main(Array * args) if (StrEquals(typeType, "struct")) { - StreamPrintf(headerFile, "extern int %sFromJson(HashMap *, %s *, char **);\n", type, type); - StreamPrintf(implFile, "int\n%sFromJson(HashMap *json, %s *out, char **errp)\n{\n", type, type); + StreamPrintf(headerFile, "extern bool %sFromJson(HashMap *, %s *, char **);\n", type, type); + StreamPrintf(implFile, "bool\n%sFromJson(HashMap *json, %s *out, char **errp)\n{\n", type, type); StreamPrintf(implFile, " JsonValue *val;\n"); StreamPrintf(implFile, " int enumParseRes;\n"); StreamPrintf(implFile, "\n"); @@ -632,14 +635,14 @@ Main(Array * args) StreamPrintf(implFile, " if (!json | !out)\n" " {\n" " *errp = \"Invalid pointers passed to %sFromJson()\";\n" - " return 0;\n" + " return false;\n" " }\n\n" ,type); for (i = 0; i < ArraySize(keys); i++) { char *key = ArrayGet(keys, i); - int required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required")); - int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); + bool required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required")); + bool ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType); @@ -656,7 +659,7 @@ Main(Array * args) StreamPrintf(implFile, " if (val)\n {\n"); StreamPrintf(implFile, " if (JsonValueType(val) != %s)\n {\n", jsonTypeStr); StreamPrintf(implFile, " *errp = \"%s.%s must be of type %s.\";\n", type, Trim('_', key), fieldType); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n\n"); if (StrEquals(fieldType, "array")) { @@ -681,7 +684,7 @@ Main(Array * args) StreamPrintf(implFile, " if (!out->%s)\n", key); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"Failed to allocate memory for %s.%s.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " else\n"); StreamPrintf(implFile, " {\n"); @@ -700,7 +703,7 @@ Main(Array * args) if (StrEquals(fieldType, "integer")) { - cType = "Int64"; + cType = "int64_t"; } else if (StrEquals(fieldType, "float")) { @@ -708,7 +711,7 @@ Main(Array * args) } else if (StrEquals(fieldType, "boolean")) { - cType = "int"; + cType = "bool"; } else { @@ -722,13 +725,13 @@ Main(Array * args) StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType)); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " ref = Malloc(sizeof(%s));\n", cType); StreamPrintf(implFile, " if (!ref)\n"); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n"); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " *ref = JsonValueAs%s(v);\n", fieldType); StreamPrintf(implFile, " ArrayAdd(out->%s, ref);\n", key); @@ -740,7 +743,7 @@ Main(Array * args) StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType)); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " ArrayAdd(out->%s, StrDuplicate(JsonValueAsString(v)));\n", key); } @@ -749,7 +752,7 @@ Main(Array * args) StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType)); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " ArrayAdd(out->%s, JsonDuplicate(JsonValueAsObject(v)));\n", key); } @@ -763,13 +766,13 @@ Main(Array * args) StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType)); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " parsed = Malloc(sizeof(%s));\n", fieldType); StreamPrintf(implFile, " if (!parsed)\n"); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n"); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); if (isEnum) { @@ -787,7 +790,7 @@ Main(Array * args) StreamPrintf(implFile, " %sFree(parsed);\n", fieldType); } StreamPrintf(implFile, " Free(parsed);\n"); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " ArrayAdd(out->%s, parsed);\n", key); } @@ -800,7 +803,7 @@ Main(Array * args) else if (jsonType == JSON_OBJECT) { StreamPrintf(implFile, " if (!%sFromJson(JsonValueAsObject(val), &out->%s, errp))\n {\n", fieldType, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); } else @@ -835,7 +838,7 @@ Main(Array * args) StreamPrintf(implFile, " if (enumParseRes == -1)\n", key); StreamPrintf(implFile, " {\n"); StreamPrintf(implFile, " *errp = \"Invalid value for %s.%s.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); StreamPrintf(implFile, " out->%s = enumParseRes;\n", key); } @@ -855,13 +858,13 @@ Main(Array * args) { StreamPrintf(implFile, " else\n {\n"); StreamPrintf(implFile, " *errp = \"%s.%s is required.\";\n", type, key); - StreamPrintf(implFile, " return 0;\n"); + StreamPrintf(implFile, " return false;\n"); StreamPrintf(implFile, " }\n"); } StreamPutc(implFile, '\n'); } - StreamPrintf(implFile, " return 1;\n"); + StreamPrintf(implFile, " return true;\n"); StreamPrintf(implFile, "}\n\n"); StreamPrintf(headerFile, "extern HashMap * %sToJson(%s *);\n", type, type); @@ -881,8 +884,8 @@ Main(Array * args) { char *key = ArrayGet(keys, i); char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type")); - int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); - int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); + bool isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum"); + bool ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore")); if (ignore) { @@ -950,7 +953,7 @@ Main(Array * args) if (StrEquals(fieldType, "integer")) { - cType = "Int64"; + cType = "int64_t"; } else if (StrEquals(fieldType, "float")) { @@ -958,7 +961,7 @@ Main(Array * args) } else if (StrEquals(fieldType, "boolean")) { - cType = "int"; + cType = "bool"; } else { From 346b912a0633cceac10780b8a103f6c89b5ba89f Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Sat, 18 May 2024 10:50:18 -0400 Subject: [PATCH 35/37] ArraySort(): Fix bound checking bug. Closes #31. --- CHANGELOG.md | 4 +++- src/Array.c | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3edab4..a646e92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ are not even initialized to a default value. specific circumstances. - Added `JsonMerge()` to the JSON API to merge two JSON objects together. - Make `HttpRouter` decode path parts before matching them on regular expressions. +- Fixed a bug in `ArraySort()` that would crash programs if the passed array has no + elements. ## v0.4.0 @@ -30,4 +32,4 @@ project with its own independent releases. This allows it to develop at a much m rapid pace than Telodendria. Changes in future releases will be reported here. Since this is the first release, -there are no changes to show. \ No newline at end of file +there are no changes to show. diff --git a/src/Array.c b/src/Array.c index c2af556..a289431 100644 --- a/src/Array.c +++ b/src/Array.c @@ -267,8 +267,9 @@ ArrayQuickSort(Array * array, size_t low, size_t high, int (*compare) (void *, v void ArraySort(Array * array, int (*compare) (void *, void *)) { - if (!array) + if (!ArraySize(array)) { + // If a NULL ptr was given, or the array has no elements, do nothing. return; } ArrayQuickSort(array, 0, array->size - 1, compare); From 9108fef7018010e6b49a111856ca0553333804f8 Mon Sep 17 00:00:00 2001 From: lda Date: Sun, 26 May 2024 15:31:14 -0500 Subject: [PATCH 36/37] Fix inconsistent sanitation with the database (#32) Cytoplasm's Db currently doesn't sanitate database entries consistently, and this PR should be a quick fix for this. Reviewed-on: https://git.telodendria.io/Telodendria/Cytoplasm/pulls/32 Co-authored-by: lda Co-committed-by: lda --- src/Db.c | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Db.c b/src/Db.c index 22456ac..4128a89 100644 --- a/src/Db.c +++ b/src/Db.c @@ -218,19 +218,38 @@ DbHashKey(Array * args) return str; } +static char +DbSanitiseChar(char input) +{ + switch (input) + { + case '/': + return '_'; + case '.': + return '-'; + } + return input; +} + static char * DbDirName(Db * db, Array * args, size_t strip) { - size_t i; + size_t i, j; char *str = StrConcat(2, db->dir, "/"); for (i = 0; i < ArraySize(args) - strip; i++) { char *tmp; + char *sanitise = StrDuplicate(ArrayGet(args, i)); + for (j = 0; j < strlen(sanitise); j++) + { + sanitise[j] = DbSanitiseChar(sanitise[j]); + } - tmp = StrConcat(3, str, ArrayGet(args, i), "/"); + tmp = StrConcat(3, str, sanitise, "/"); Free(str); + Free(sanitise); str = tmp; } @@ -253,17 +272,7 @@ DbFileName(Db * db, Array * args) /* Sanitize name to prevent directory traversal attacks */ while (arg[j]) { - switch (arg[j]) - { - case '/': - arg[j] = '_'; - break; - case '.': - arg[j] = '-'; - break; - default: - break; - } + arg[j] = DbSanitiseChar(arg[j]); j++; } From d983296dd268e8210529f946cc3041b8a845bbb1 Mon Sep 17 00:00:00 2001 From: lda Date: Mon, 3 Jun 2024 19:42:09 +0200 Subject: [PATCH 37/37] [MOD] As it turns out, you do need to free thr fd. --- src/Tls/TlsOpenSSL.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Tls/TlsOpenSSL.c b/src/Tls/TlsOpenSSL.c index c056ebc..07b7bd5 100644 --- a/src/Tls/TlsOpenSSL.c +++ b/src/Tls/TlsOpenSSL.c @@ -295,9 +295,7 @@ TlsClose(void *cookie) SSL_free(ssl->ssl); SSL_CTX_free(ssl->ctx); -#if 0 close(ssl->fd); -#endif Free(ssl);