forked from Telodendria/Cytoplasm
Compare commits
No commits in common. "102ea9409d65b02e9007461115f6aebe037c7cfd" and "c3429f035cb275dc3d43cc1a100ac3eda77742f8" have entirely different histories.
102ea9409d
...
c3429f035c
68 changed files with 136 additions and 147 deletions
|
@ -19,8 +19,6 @@ are not even initialized to a default value.
|
||||||
specific circumstances.
|
specific circumstances.
|
||||||
- Added `JsonMerge()` to the JSON API to merge two JSON objects together.
|
- Added `JsonMerge()` to the JSON API to merge two JSON objects together.
|
||||||
- Make `HttpRouter` decode path parts before matching them on regular expressions.
|
- 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
|
## v0.4.0
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
30
README.md
30
README.md
|
@ -1,15 +1,15 @@
|
||||||
<p align="center"><img src="https://telodendria.io/user/themes/bancino/images/logo/Cytoplasm.png"></p>
|
<p align="center"><img src="https://telodendria.io/assets/Cytoplasm.png"></p>
|
||||||
<h1 align="center">Cytoplasm (<code>libcytoplasm</code>)</h1>
|
<h1 align="center">Cytoplasm (<code>libcytoplasm</code>)</h1>
|
||||||
|
|
||||||
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 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. 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 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 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 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 safety, this inevitably adds a little overhead, which may be unsuitable for time- or space-critical tasks.
|
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 ([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.
|
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 beyond what the C standard library provides.
|
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,7 +17,14 @@ Cytoplasm also starts with a C, which I think is a nice touch for C libraries. I
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
||||||
- OpenSSL
|
- OpenSSL
|
||||||
- LibreSSL
|
- LibreSSL
|
||||||
|
@ -53,11 +60,14 @@ 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.
|
- `--with-(openssl|libressl)`: Select the TLS implementation to use. OpenSSL is selected by default.
|
||||||
- `--disable-tls`: Disable TLS altogether.
|
- `--disable-tls`: Disable TLS altogether.
|
||||||
- `--prefix=<path>`: 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.
|
- `--prefix=<path>`: 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.
|
- `--(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:
|
Cytoplasm can be customized with the following options:
|
||||||
|
|
||||||
- `--lib-name=<name>`: The output name of the library. This defaults to `Cytoplasm` and should in most cases not be changed.
|
- `--lib-name=<name>`: The output name of the library. This defaults to `Cytoplasm` and should in most cases not be changed.
|
||||||
|
- `--lib-version=<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`:
|
The following recipes are available in the generated `Makefile`:
|
||||||
|
|
||||||
|
@ -86,13 +96,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:
|
Here is the canonical Hello World written with Cytoplasm:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
#include <Cytoplasm/Log.h>
|
#include <Cytoplasm/Log.h>
|
||||||
|
|
||||||
int Main(void)
|
int Main(void)
|
||||||
{
|
{
|
||||||
Log(LOG_INFO, "Hello World!");
|
Log(LOG_INFO, "Hello World!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If this file is `Hello.c`, then you can compile it by doing this:
|
If this file is `Hello.c`, then you can compile it by doing this:
|
||||||
|
|
16
configure
vendored
16
configure
vendored
|
@ -10,7 +10,7 @@ echo "-------------------"
|
||||||
BUILD="build"
|
BUILD="build"
|
||||||
OUT="out"
|
OUT="out"
|
||||||
SRC="src"
|
SRC="src"
|
||||||
INCLUDE="include/Cytoplasm"
|
INCLUDE="src/include"
|
||||||
TOOLS="tools"
|
TOOLS="tools"
|
||||||
|
|
||||||
# Default compiler flags. These must be supported by all POSIX C compilers.
|
# Default compiler flags. These must be supported by all POSIX C compilers.
|
||||||
|
@ -63,7 +63,7 @@ for arg in $SCRIPT_ARGS; do
|
||||||
gcc*|clang*)
|
gcc*|clang*)
|
||||||
# "Fancy" compilers that support a plethora of additional flags we
|
# "Fancy" compilers that support a plethora of additional flags we
|
||||||
# want to enable if present.
|
# want to enable if present.
|
||||||
CFLAGS="-Wall -Wextra -Werror -pedantic -std=c99 -O3 ${CFLAGS}"
|
CFLAGS="-Wall -Werror -pedantic -std=c99 ${CFLAGS}"
|
||||||
LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections"
|
LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -184,28 +184,22 @@ compile_doc() {
|
||||||
install_out() {
|
install_out() {
|
||||||
src="$1"
|
src="$1"
|
||||||
out="$2"
|
out="$2"
|
||||||
dir=$(dirname "$out")
|
|
||||||
|
|
||||||
echo "${TAB}mkdir -p \"$dir\""
|
echo "${TAB}install -D \"$src\" \"$out\""
|
||||||
echo "${TAB}cp \"$src\" \"$out\""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_man() {
|
install_man() {
|
||||||
src="${OUT}/man/man3/${LIB_NAME}-$(basename $1 .h).3"
|
src="${OUT}/man/man3/${LIB_NAME}-$(basename $1 .h).3"
|
||||||
out="$2"
|
out="$2"
|
||||||
dir=$(dirname "$out")
|
|
||||||
|
|
||||||
echo "${TAB}mkdir -p \"$dir\""
|
echo "${TAB}install -D \"$src\" \"$out\""
|
||||||
echo "${TAB}cp \"$src\" \"$out\""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_tool() {
|
install_tool() {
|
||||||
src=${OUT}/bin/$(basename "$1" .c)
|
src=${OUT}/bin/$(basename "$1" .c)
|
||||||
out="$2"
|
out="$2"
|
||||||
dir=$(dirname "$out")
|
|
||||||
|
|
||||||
echo "${TAB}mkdir -p \"$dir\""
|
echo "${TAB}install -D \"$src\" \"$out\""
|
||||||
echo "${TAB}cp \"$src\" \"$out\""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_out() {
|
uninstall_out() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -267,9 +267,8 @@ ArrayQuickSort(Array * array, size_t low, size_t high, int (*compare) (void *, v
|
||||||
void
|
void
|
||||||
ArraySort(Array * array, int (*compare) (void *, void *))
|
ArraySort(Array * array, int (*compare) (void *, void *))
|
||||||
{
|
{
|
||||||
if (!ArraySize(array))
|
if (!array)
|
||||||
{
|
{
|
||||||
// If a NULL ptr was given, or the array has no elements, do nothing.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ArrayQuickSort(array, 0, array->size - 1, compare);
|
ArrayQuickSort(array, 0, array->size - 1, compare);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
37
src/Db.c
37
src/Db.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -218,38 +218,19 @@ DbHashKey(Array * args)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char
|
|
||||||
DbSanitiseChar(char input)
|
|
||||||
{
|
|
||||||
switch (input)
|
|
||||||
{
|
|
||||||
case '/':
|
|
||||||
return '_';
|
|
||||||
case '.':
|
|
||||||
return '-';
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
DbDirName(Db * db, Array * args, size_t strip)
|
DbDirName(Db * db, Array * args, size_t strip)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i;
|
||||||
char *str = StrConcat(2, db->dir, "/");
|
char *str = StrConcat(2, db->dir, "/");
|
||||||
|
|
||||||
for (i = 0; i < ArraySize(args) - strip; i++)
|
for (i = 0; i < ArraySize(args) - strip; i++)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
char *sanitise = ArrayGet(args, i);
|
|
||||||
for (j = 0; j < strlen(sanitise); j++)
|
|
||||||
{
|
|
||||||
sanitise[j] = DbSanitiseChar(sanitise[j]);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = StrConcat(3, str, sanitise, "/");
|
tmp = StrConcat(3, str, ArrayGet(args, i), "/");
|
||||||
|
|
||||||
Free(str);
|
Free(str);
|
||||||
Free(sanitise);
|
|
||||||
|
|
||||||
str = tmp;
|
str = tmp;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +253,17 @@ DbFileName(Db * db, Array * args)
|
||||||
/* Sanitize name to prevent directory traversal attacks */
|
/* Sanitize name to prevent directory traversal attacks */
|
||||||
while (arg[j])
|
while (arg[j])
|
||||||
{
|
{
|
||||||
arg[j] = DbSanitiseChar(arg[j]);
|
switch (arg[j])
|
||||||
|
{
|
||||||
|
case '/':
|
||||||
|
arg[j] = '_';
|
||||||
|
break;
|
||||||
|
case '.':
|
||||||
|
arg[j] = '-';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
2
src/Io.c
2
src/Io.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
63
tools/j2s.c
63
tools/j2s.c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -25,7 +25,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
#include <Array.h>
|
#include <Array.h>
|
||||||
|
@ -324,7 +323,7 @@ Main(Array * args)
|
||||||
while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal))
|
while (HashMapIterate(typeFields, &fieldName, (void **) &fieldVal))
|
||||||
{
|
{
|
||||||
char *fieldType;
|
char *fieldType;
|
||||||
bool isArrType = false;
|
int isArrType = 0;
|
||||||
JsonValue *requiredVal;
|
JsonValue *requiredVal;
|
||||||
JsonValue *ignoreVal;
|
JsonValue *ignoreVal;
|
||||||
|
|
||||||
|
@ -347,7 +346,7 @@ Main(Array * args)
|
||||||
{
|
{
|
||||||
fieldType++;
|
fieldType++;
|
||||||
fieldType[strlen(fieldType) - 1] = '\0';
|
fieldType[strlen(fieldType) - 1] = '\0';
|
||||||
isArrType = true;
|
isArrType = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StrEquals(fieldType, "object") &&
|
if (!StrEquals(fieldType, "object") &&
|
||||||
|
@ -460,11 +459,9 @@ Main(Array * args)
|
||||||
StreamPrintf(headerFile, "#ifndef %s\n", guard);
|
StreamPrintf(headerFile, "#ifndef %s\n", guard);
|
||||||
StreamPrintf(headerFile, "#define %s\n\n", guard);
|
StreamPrintf(headerFile, "#define %s\n\n", guard);
|
||||||
|
|
||||||
StreamPrintf(headerFile, "#include <stdint.h>\n");
|
|
||||||
StreamPrintf(headerFile, "#include <stdbool.h>\n");
|
|
||||||
|
|
||||||
StreamPrintf(headerFile, "#include <Cytoplasm/Array.h>\n");
|
StreamPrintf(headerFile, "#include <Cytoplasm/Array.h>\n");
|
||||||
StreamPrintf(headerFile, "#include <Cytoplasm/HashMap.h>\n");
|
StreamPrintf(headerFile, "#include <Cytoplasm/HashMap.h>\n");
|
||||||
|
StreamPrintf(headerFile, "#include <Cytoplasm/Int64.h>\n");
|
||||||
|
|
||||||
StreamPutc(headerFile, '\n');
|
StreamPutc(headerFile, '\n');
|
||||||
|
|
||||||
|
@ -519,11 +516,11 @@ Main(Array * args)
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "integer"))
|
else if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "int64_t";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "boolean"))
|
else if (StrEquals(fieldType, "boolean"))
|
||||||
{
|
{
|
||||||
cType = "bool";
|
cType = "int";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "float"))
|
else if (StrEquals(fieldType, "float"))
|
||||||
{
|
{
|
||||||
|
@ -625,8 +622,8 @@ Main(Array * args)
|
||||||
|
|
||||||
if (StrEquals(typeType, "struct"))
|
if (StrEquals(typeType, "struct"))
|
||||||
{
|
{
|
||||||
StreamPrintf(headerFile, "extern bool %sFromJson(HashMap *, %s *, char **);\n", type, type);
|
StreamPrintf(headerFile, "extern int %sFromJson(HashMap *, %s *, char **);\n", type, type);
|
||||||
StreamPrintf(implFile, "bool\n%sFromJson(HashMap *json, %s *out, char **errp)\n{\n", type, type);
|
StreamPrintf(implFile, "int\n%sFromJson(HashMap *json, %s *out, char **errp)\n{\n", type, type);
|
||||||
StreamPrintf(implFile, " JsonValue *val;\n");
|
StreamPrintf(implFile, " JsonValue *val;\n");
|
||||||
StreamPrintf(implFile, " int enumParseRes;\n");
|
StreamPrintf(implFile, " int enumParseRes;\n");
|
||||||
StreamPrintf(implFile, "\n");
|
StreamPrintf(implFile, "\n");
|
||||||
|
@ -635,14 +632,14 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (!json | !out)\n"
|
StreamPrintf(implFile, " if (!json | !out)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" *errp = \"Invalid pointers passed to %sFromJson()\";\n"
|
" *errp = \"Invalid pointers passed to %sFromJson()\";\n"
|
||||||
" return false;\n"
|
" return 0;\n"
|
||||||
" }\n\n"
|
" }\n\n"
|
||||||
,type);
|
,type);
|
||||||
for (i = 0; i < ArraySize(keys); i++)
|
for (i = 0; i < ArraySize(keys); i++)
|
||||||
{
|
{
|
||||||
char *key = ArrayGet(keys, i);
|
char *key = ArrayGet(keys, i);
|
||||||
bool required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required"));
|
int required = JsonValueAsBoolean(JsonGet(fields, 2, key, "required"));
|
||||||
bool ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
|
int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
|
||||||
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
|
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
|
||||||
int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
|
int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
|
||||||
JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType);
|
JsonType jsonType = isEnum ? JSON_STRING : TypeToJsonType(fieldType);
|
||||||
|
@ -659,7 +656,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (val)\n {\n");
|
StreamPrintf(implFile, " if (val)\n {\n");
|
||||||
StreamPrintf(implFile, " if (JsonValueType(val) != %s)\n {\n", jsonTypeStr);
|
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, " *errp = \"%s.%s must be of type %s.\";\n", type, Trim('_', key), fieldType);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n\n");
|
StreamPrintf(implFile, " }\n\n");
|
||||||
if (StrEquals(fieldType, "array"))
|
if (StrEquals(fieldType, "array"))
|
||||||
{
|
{
|
||||||
|
@ -684,7 +681,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (!out->%s)\n", key);
|
StreamPrintf(implFile, " if (!out->%s)\n", key);
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"Failed to allocate memory for %s.%s.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"Failed to allocate memory for %s.%s.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " else\n");
|
StreamPrintf(implFile, " else\n");
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
|
@ -703,7 +700,7 @@ Main(Array * args)
|
||||||
|
|
||||||
if (StrEquals(fieldType, "integer"))
|
if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "int64_t";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "float"))
|
else if (StrEquals(fieldType, "float"))
|
||||||
{
|
{
|
||||||
|
@ -711,7 +708,7 @@ Main(Array * args)
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "boolean"))
|
else if (StrEquals(fieldType, "boolean"))
|
||||||
{
|
{
|
||||||
cType = "bool";
|
cType = "int";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -725,13 +722,13 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " ref = Malloc(sizeof(%s));\n", cType);
|
StreamPrintf(implFile, " ref = Malloc(sizeof(%s));\n", cType);
|
||||||
StreamPrintf(implFile, " if (!ref)\n");
|
StreamPrintf(implFile, " if (!ref)\n");
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n");
|
StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n");
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " *ref = JsonValueAs%s(v);\n", fieldType);
|
StreamPrintf(implFile, " *ref = JsonValueAs%s(v);\n", fieldType);
|
||||||
StreamPrintf(implFile, " ArrayAdd(out->%s, ref);\n", key);
|
StreamPrintf(implFile, " ArrayAdd(out->%s, ref);\n", key);
|
||||||
|
@ -743,7 +740,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " ArrayAdd(out->%s, StrDuplicate(JsonValueAsString(v)));\n", key);
|
StreamPrintf(implFile, " ArrayAdd(out->%s, StrDuplicate(JsonValueAsString(v)));\n", key);
|
||||||
}
|
}
|
||||||
|
@ -752,7 +749,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " ArrayAdd(out->%s, JsonDuplicate(JsonValueAsObject(v)));\n", key);
|
StreamPrintf(implFile, " ArrayAdd(out->%s, JsonDuplicate(JsonValueAsObject(v)));\n", key);
|
||||||
}
|
}
|
||||||
|
@ -766,13 +763,13 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
StreamPrintf(implFile, " if (JsonValueType(v) != %s)\n", JsonTypeToStr(jsonType));
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"%s.%s[] contains an invalid value.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " parsed = Malloc(sizeof(%s));\n", fieldType);
|
StreamPrintf(implFile, " parsed = Malloc(sizeof(%s));\n", fieldType);
|
||||||
StreamPrintf(implFile, " if (!parsed)\n");
|
StreamPrintf(implFile, " if (!parsed)\n");
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n");
|
StreamPrintf(implFile, " *errp = \"Unable to allocate memory for array value.\";\n");
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
if (isEnum)
|
if (isEnum)
|
||||||
{
|
{
|
||||||
|
@ -790,7 +787,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " %sFree(parsed);\n", fieldType);
|
StreamPrintf(implFile, " %sFree(parsed);\n", fieldType);
|
||||||
}
|
}
|
||||||
StreamPrintf(implFile, " Free(parsed);\n");
|
StreamPrintf(implFile, " Free(parsed);\n");
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " ArrayAdd(out->%s, parsed);\n", key);
|
StreamPrintf(implFile, " ArrayAdd(out->%s, parsed);\n", key);
|
||||||
}
|
}
|
||||||
|
@ -803,7 +800,7 @@ Main(Array * args)
|
||||||
else if (jsonType == JSON_OBJECT)
|
else if (jsonType == JSON_OBJECT)
|
||||||
{
|
{
|
||||||
StreamPrintf(implFile, " if (!%sFromJson(JsonValueAsObject(val), &out->%s, errp))\n {\n", fieldType, key);
|
StreamPrintf(implFile, " if (!%sFromJson(JsonValueAsObject(val), &out->%s, errp))\n {\n", fieldType, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -838,7 +835,7 @@ Main(Array * args)
|
||||||
StreamPrintf(implFile, " if (enumParseRes == -1)\n", key);
|
StreamPrintf(implFile, " if (enumParseRes == -1)\n", key);
|
||||||
StreamPrintf(implFile, " {\n");
|
StreamPrintf(implFile, " {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"Invalid value for %s.%s.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"Invalid value for %s.%s.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
StreamPrintf(implFile, " out->%s = enumParseRes;\n", key);
|
StreamPrintf(implFile, " out->%s = enumParseRes;\n", key);
|
||||||
}
|
}
|
||||||
|
@ -858,13 +855,13 @@ Main(Array * args)
|
||||||
{
|
{
|
||||||
StreamPrintf(implFile, " else\n {\n");
|
StreamPrintf(implFile, " else\n {\n");
|
||||||
StreamPrintf(implFile, " *errp = \"%s.%s is required.\";\n", type, key);
|
StreamPrintf(implFile, " *errp = \"%s.%s is required.\";\n", type, key);
|
||||||
StreamPrintf(implFile, " return false;\n");
|
StreamPrintf(implFile, " return 0;\n");
|
||||||
StreamPrintf(implFile, " }\n");
|
StreamPrintf(implFile, " }\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamPutc(implFile, '\n');
|
StreamPutc(implFile, '\n');
|
||||||
}
|
}
|
||||||
StreamPrintf(implFile, " return true;\n");
|
StreamPrintf(implFile, " return 1;\n");
|
||||||
StreamPrintf(implFile, "}\n\n");
|
StreamPrintf(implFile, "}\n\n");
|
||||||
|
|
||||||
StreamPrintf(headerFile, "extern HashMap * %sToJson(%s *);\n", type, type);
|
StreamPrintf(headerFile, "extern HashMap * %sToJson(%s *);\n", type, type);
|
||||||
|
@ -884,8 +881,8 @@ Main(Array * args)
|
||||||
{
|
{
|
||||||
char *key = ArrayGet(keys, i);
|
char *key = ArrayGet(keys, i);
|
||||||
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
|
char *fieldType = JsonValueAsString(JsonGet(fields, 2, key, "type"));
|
||||||
bool isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
|
int isEnum = StrEquals(JsonValueAsString(JsonGet(types, 2, fieldType, "type")), "enum");
|
||||||
bool ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
|
int ignore = JsonValueAsBoolean(JsonGet(fields, 2, key, "ignore"));
|
||||||
|
|
||||||
if (ignore)
|
if (ignore)
|
||||||
{
|
{
|
||||||
|
@ -953,7 +950,7 @@ Main(Array * args)
|
||||||
|
|
||||||
if (StrEquals(fieldType, "integer"))
|
if (StrEquals(fieldType, "integer"))
|
||||||
{
|
{
|
||||||
cType = "int64_t";
|
cType = "Int64";
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "float"))
|
else if (StrEquals(fieldType, "float"))
|
||||||
{
|
{
|
||||||
|
@ -961,7 +958,7 @@ Main(Array * args)
|
||||||
}
|
}
|
||||||
else if (StrEquals(fieldType, "boolean"))
|
else if (StrEquals(fieldType, "boolean"))
|
||||||
{
|
{
|
||||||
cType = "bool";
|
cType = "int";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
Loading…
Reference in a new issue