Compare commits
112 Commits
Telodendri
...
master
Author | SHA1 | Date |
---|---|---|
|
2c6d5194d2 | |
|
0a91a0c40b | |
|
d3dcf334f0 | |
|
3dae19e82d | |
|
2d30719be4 | |
|
503bfb6104 | |
|
77800e4117 | |
|
db4ae0408c | |
|
edee1288d8 | |
|
4b90800a2b | |
|
6e7f170768 | |
|
1f02f3c2a2 | |
|
582c79b608 | |
|
42a901b7f5 | |
|
1fee47a628 | |
|
6377689a83 | |
|
23237f97b5 | |
|
82ae2d4e41 | |
|
7d3d84d969 | |
|
bf1ce839d0 | |
|
f8d3e54fec | |
|
cb41716bf3 | |
|
6247085df1 | |
|
0172fa083b | |
|
0b820b80f7 | |
|
6dcfa7dc02 | |
|
024482d4e8 | |
|
7a091c5b93 | |
|
9e8523d92e | |
|
419017bcc9 | |
|
1a009e87c3 | |
|
08594e0fb1 | |
|
56508afe4c | |
|
ac3582ddeb | |
|
61f7ab1040 | |
|
a672c05112 | |
|
09023089f5 | |
|
6d6fd1645c | |
|
043c2e9e33 | |
|
9e2f047e82 | |
|
c78d075a93 | |
|
e4a217550f | |
|
d50372a91a | |
|
fa3b5e95bd | |
|
7033a1f0b1 | |
|
f6c54cbc7f | |
|
3cb04417ff | |
|
93e6582db5 | |
|
ee62d31c68 | |
|
4bd527aa9a | |
|
79ce36c860 | |
|
be3ee54bd8 | |
![]() |
5367ffca96 | |
|
c5b2fcf586 | |
|
2b43a93524 | |
|
fd28f97449 | |
|
745a208f14 | |
|
8843b34ba6 | |
|
b059f966f1 | |
|
8bf8afd91d | |
|
6db3f3c612 | |
|
fd1172ff56 | |
|
468656eee6 | |
|
b625655439 | |
|
dab666c969 | |
|
36413b4dca | |
|
1c32e18c74 | |
|
2382638005 | |
|
38a303da91 | |
|
2f76d5b9ae | |
|
93c4b6bfc4 | |
|
d565640455 | |
|
bc71a7ec01 | |
|
69d28f39d1 | |
|
e0af88145e | |
|
6ef965d1e0 | |
|
28d9e1cb3b | |
|
78302d6320 | |
|
6ec87b8d76 | |
|
5f3220372e | |
|
77d71989df | |
|
e9600a21e9 | |
|
942d2aad18 | |
|
aeaa8487c3 | |
|
ed37afe564 | |
|
2e193d4bcf | |
|
d22baf440f | |
|
c467d0913d | |
|
68b644a4f2 | |
|
b65394ab50 | |
|
a958c4a529 | |
|
c96ac30f28 | |
|
a4330123b9 | |
|
b1c23ee53a | |
|
bc8283f844 | |
|
5f34b846ee | |
|
3054a80906 | |
|
539fde773f | |
|
1fa07d2d3c | |
|
80da024e4e | |
|
e3badbd55c | |
|
861d4146c0 | |
|
f9e1250d47 | |
|
4e184102cb | |
|
8bda70b1fb | |
|
8f0d197480 | |
|
b9641e89d6 | |
|
1381a31cbd | |
|
c3287c1674 | |
|
071a86114c | |
|
1f14169284 | |
|
2f946848cb |
|
@ -1,6 +0,0 @@
|
|||
build
|
||||
data
|
||||
.env
|
||||
*.patch
|
||||
*.log
|
||||
vgcore.*
|
|
@ -0,0 +1,49 @@
|
|||
name: Bug Report
|
||||
about: File a bug report regarding Telodendria, its website, or its documentation.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
You are submitting a bug report. Please be sure to fill out the
|
||||
title with a brief description of the bug.
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: Type
|
||||
description: Select the type of issue.
|
||||
options:
|
||||
- Memory Leak
|
||||
- Crash
|
||||
- Unexpected Error Message
|
||||
- Documentation
|
||||
- Website
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please give a thorough and detailed description of the bug you
|
||||
are reporting. Provide all the information you have, and do
|
||||
some investigating to ensure you are providing a legitimate
|
||||
issue report that is well thought out. **Include details on
|
||||
how to reproduce the issue, or explicitly state that you were
|
||||
unable to reproduce it.**
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Log Output
|
||||
description: |
|
||||
Please copy and paste the relevant sections of the log output,
|
||||
or the entire log if it is not unreasonably large. The logs
|
||||
will be automatically formatted, no code block is necessary.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Please attach any additional files that may aid in our
|
||||
investigation of this issue, including screenshots, debugging
|
||||
session stack traces and dumps, etc.
|
|
@ -0,0 +1,7 @@
|
|||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: General Matrix Room
|
||||
url: "https://matrix.to/#/#telodendria-general:bancino.net"
|
||||
about: |
|
||||
General discussion on Telodendria happens in this Matrix room. You
|
||||
may get quicker feedback from there.
|
|
@ -0,0 +1,18 @@
|
|||
name: Feature Request
|
||||
about: Request a new feature or enhancement be added to Telodendria.
|
||||
title: "[Feature] "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
You are submitting a feature request. Please be sure to fill
|
||||
out the title with a brief description of the feature you are
|
||||
requesting.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: |
|
||||
Please give a thorough and detailed description of the feature
|
||||
you are requesting.
|
||||
validations:
|
||||
required: true
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
---
|
||||
|
||||
Please review the developer certificate of origin:
|
||||
|
||||
1. The contribution was created in whole or in part by me, and I have
|
||||
the right to submit it under the open source licenses of the
|
||||
Telodendria project; or
|
||||
1. The contribution is based upon a previous work that, to the best of
|
||||
my knowledge, is covered under an appropriate open source license and
|
||||
I have the right under that license to submit that work with
|
||||
modifications, whether created in whole or in part by me, under the
|
||||
Telodendria project license; or
|
||||
1. The contribution was provided directly to me by some other person
|
||||
who certified (1), (2), or (3), and I have not modified it.
|
||||
1. I understand and agree that this project and the contribution are
|
||||
made public and that a record of the contribution—including all
|
||||
personal information I submit with it—is maintained indefinitely
|
||||
and may be redistributed consistent with this project or the open
|
||||
source licenses involved.
|
||||
|
||||
- [ ] I have read the Telodendria Project development certificate of
|
||||
origin, and I certify that I have permission to submit this patch
|
||||
under the conditions specified in it.
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# Telodendria .gitignore
|
||||
|
||||
build
|
||||
out
|
||||
data
|
||||
Makefile
|
||||
|
||||
*-leaked.txt
|
||||
.env
|
||||
*.patch
|
||||
*.orig
|
||||
*.log
|
||||
vgcore.*
|
||||
*.core
|
||||
contrib/.vagrant
|
||||
src/Schema
|
||||
src/include/Schema
|
||||
man/mandoc.db
|
|
@ -1,3 +0,0 @@
|
|||
build
|
||||
out
|
||||
*-leaked.txt
|
|
@ -1,28 +0,0 @@
|
|||
-bad
|
||||
-bap
|
||||
-bbb
|
||||
-nbc
|
||||
-bl
|
||||
-c36
|
||||
-cd36
|
||||
-ncdb
|
||||
-nce
|
||||
-ci8
|
||||
-cli1
|
||||
-d0
|
||||
-di1
|
||||
-ndj
|
||||
-ei
|
||||
-fc1
|
||||
-i4
|
||||
-ip
|
||||
-l72
|
||||
-lc72
|
||||
-lp
|
||||
-npcs
|
||||
-psl
|
||||
-sc
|
||||
-nsob
|
||||
-nut
|
||||
-nv
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
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 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 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
------------------------------------------------------------------------
|
||||
|
||||
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:
|
||||
|
||||
* 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:
|
||||
|
||||
$ sh make.sh
|
||||
|
||||
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.
|
||||
man/ - All Cytoplasm API documentation.
|
||||
|
||||
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.
|
||||
|
||||
Here is the canonical Hello World written with Cytoplasm:
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
int Main(void)
|
||||
{
|
||||
Log(LOG_INFO, "Hello World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
If this file is Hello.c, then you can compile it by doing something
|
||||
like this:
|
||||
|
||||
$ cc -o hello Hello.c cytoplasm.o -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:
|
||||
|
||||
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.
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
#include <Array.h>
|
||||
#include <HashMap.h>
|
||||
|
||||
#include <Log.h>
|
||||
|
||||
int
|
||||
Main(Array * args, HashMap * env)
|
||||
{
|
||||
size_t i;
|
||||
char *key;
|
||||
char *val;
|
||||
|
||||
Log(LOG_INFO, "Hello World!");
|
||||
Log(LOG_INFO, "Arguments: %lu", ArraySize(args));
|
||||
|
||||
for (i = 0; i < ArraySize(args); i++)
|
||||
{
|
||||
Log(LOG_INFO, " [%ld] %s", i, ArrayGet(args, i));
|
||||
}
|
||||
|
||||
Log(LOG_INFO, "Environment:");
|
||||
while (HashMapIterate(env, &key, (void **) &val))
|
||||
{
|
||||
Log(LOG_INFO, " %s = %s", key, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
addprefix() {
|
||||
prefix="$1"
|
||||
shift
|
||||
for thing in "$@"; do
|
||||
echo "${prefix}${thing}"
|
||||
done
|
||||
|
||||
unset prefix
|
||||
unset thing
|
||||
}
|
||||
|
||||
: "${NAME:=Cytoplasm}"
|
||||
: "${LIB_NAME:=$(echo ${NAME} | tr '[A-Z]' '[a-z]')}"
|
||||
: "${VERSION:=0.3.0}"
|
||||
|
||||
: "${CVS_TAG:=${NAME}-$(echo ${VERSION} | sed 's/\./_/g')}"
|
||||
|
||||
|
||||
: "${SRC:=src}"
|
||||
: "${TOOLS:=tools}"
|
||||
: "${EXAMPLES:=examples}"
|
||||
: "${BUILD:=build}"
|
||||
: "${OUT:=out}"
|
||||
: "${STUB:=RtStub}"
|
||||
: "${LICENSE:=LICENSE.txt}"
|
||||
|
||||
: "${CC:=cc}"
|
||||
: "${AR:=ar}"
|
||||
|
||||
: "${DEFINES:=-D_DEFAULT_SOURCE -DLIB_NAME=\"${NAME}\" -DLIB_VERSION=\"${VERSION}\"}"
|
||||
: "${INCLUDE:=${SRC}/include}"
|
||||
|
||||
: "${CFLAGS:=-Wall -Wextra -pedantic -std=c89 -O3 -pipe}"
|
||||
: "${LD_EXTRA:=-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections}"
|
||||
: "${LDFLAGS:=-lm -pthread}"
|
||||
|
||||
if [ "${DEBUG}" = "1" ]; then
|
||||
CFLAGS="${CFLAGS} -O0 -g"
|
||||
LD_EXTRA=""
|
||||
fi
|
||||
|
||||
if [ -n "${TLS_IMPL}" ]; then
|
||||
case "${TLS_IMPL}" in
|
||||
"LIBRESSL")
|
||||
TLS_LIBS="-ltls -lcrypto -lssl"
|
||||
;;
|
||||
"OPENSSL")
|
||||
TLS_LIBS="-lcrypto -lssl"
|
||||
;;
|
||||
*)
|
||||
echo "Unrecognized TLS implementation: ${TLS_IMPL}"
|
||||
echo "Consult Tls.h for supported implementations."
|
||||
echo "Note that the TLS_ prefix is omitted in TLS_IMPL."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
DEFINES="${DEFINES} -DTLS_IMPL=TLS_${TLS_IMPL}"
|
||||
LDFLAGS="${LDFLAGS} ${TLS_LIBS}"
|
||||
fi
|
||||
|
||||
CFLAGS="${CFLAGS} ${DEFINES} $(addprefix -I$(pwd)/ ${INCLUDE})"
|
||||
LDFLAGS="${LDFLAGS} ${LD_EXTRA}"
|
||||
|
||||
# Check the modificiation time of a file. This is used to do
|
||||
# incremental builds; we only want to rebuild files that have
|
||||
# have changed.
|
||||
mod_time() {
|
||||
if [ -n "$1" ] && [ -f "$1" ]; then
|
||||
case "$(uname)" in
|
||||
Linux | CYGWIN_NT* | Haiku)
|
||||
stat -c %Y "$1"
|
||||
;;
|
||||
*BSD | DragonFly | Minix)
|
||||
stat -f %m "$1"
|
||||
;;
|
||||
*)
|
||||
# Platform unknown, force rebuilding the whole
|
||||
# project every time.
|
||||
echo "0"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
# Substitute shell variables in a stream with their actual value
|
||||
# in this shell.
|
||||
setsubst() {
|
||||
SED="/tmp/sed-$RANDOM.txt"
|
||||
|
||||
(
|
||||
set | while IFS='=' read -r var val; do
|
||||
val=$(echo "$val" | cut -d "'" -f 2- | rev | cut -d "'" -f 2- | rev)
|
||||
echo "s|\\\${$var}|$val|g"
|
||||
done
|
||||
|
||||
echo "s|\\\${[a-zA-Z_]*}||g"
|
||||
echo "s|'''|'|g"
|
||||
) >"$SED"
|
||||
|
||||
sed -f "$SED" $@
|
||||
rm "$SED"
|
||||
}
|
||||
|
||||
recipe_docs() {
|
||||
export LD_LIBRARY_PATH="${OUT}/lib"
|
||||
mkdir -p "${OUT}/man/man3"
|
||||
|
||||
for header in $(find ${INCLUDE} -name '*.h'); do
|
||||
basename=$(basename "$header")
|
||||
man=$(echo "${OUT}/man/man3/$basename" | sed -e 's/\.h$/\.3/')
|
||||
|
||||
if [ $(mod_time "$header") -ge $(mod_time "$man") ]; then
|
||||
echo "DOC $basename"
|
||||
if ! "${OUT}/bin/hdoc" -D "Os=${NAME}" -i "$header" -o "$man"; then
|
||||
rm "$man"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if which makewhatis 2>&1 > /dev/null; then
|
||||
makewhatis "${OUT}/man"
|
||||
fi
|
||||
}
|
||||
|
||||
recipe_libs() {
|
||||
echo "-lm -pthread ${TLS_LIBS}"
|
||||
}
|
||||
|
||||
recipe_build() {
|
||||
mkdir -p "${BUILD}" "${OUT}/bin" "${OUT}/lib"
|
||||
cd "${SRC}"
|
||||
|
||||
|
||||
echo "CC = ${CC}"
|
||||
echo "CFLAGS = ${CFLAGS}"
|
||||
echo "LDFLAGS = ${LDFLAGS}"
|
||||
echo
|
||||
|
||||
do_rebuild=0
|
||||
objs=""
|
||||
for src in $(find . -name '*.c' | cut -d '/' -f 2-); do
|
||||
obj=$(echo "${BUILD}/$src" | sed -e 's/\.c$/\.o/')
|
||||
|
||||
if [ $(basename "$obj" .o) != "${STUB}" ]; then
|
||||
objs="$objs $obj"
|
||||
fi
|
||||
|
||||
if [ $(mod_time "$src") -ge $(mod_time "../$obj") ]; then
|
||||
echo "CC $(basename $obj)"
|
||||
obj_dir=$(dirname "../$obj")
|
||||
mkdir -p "$obj_dir"
|
||||
if ! $CC $CFLAGS -fPIC -c -o "../$obj" "$src"; then
|
||||
exit 1
|
||||
fi
|
||||
do_rebuild=1
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
if [ $do_rebuild -eq 1 ] || [ ! -f "${OUT}/lib/lib${LIB_NAME}.a" ]; then
|
||||
echo "AR lib${LIB_NAME}.a"
|
||||
if ! $AR rcs "${OUT}/lib/lib${LIB_NAME}.a" $objs; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $do_rebuild -eq 1 ] || [ ! -f "${OUT}/lib/lib${LIB_NAME}.so" ]; then
|
||||
echo "LD lib${LIB_NAME}.so"
|
||||
if ! $CC -shared -o "${OUT}/lib/lib${LIB_NAME}.so" $objs ${LDFLAGS}; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cp "${BUILD}/${STUB}.o" "${OUT}/lib/${LIB_NAME}.o"
|
||||
|
||||
for src in $(find "${TOOLS}" -name '*.c'); do
|
||||
out=$(basename "$src" .c)
|
||||
out="${OUT}/bin/$out"
|
||||
|
||||
if [ $(mod_time "$src") -ge $(mod_time "$out") ] || [ $do_rebuild -eq 1 ]; then
|
||||
echo "CC $(basename $out)"
|
||||
mkdir -p "$(dirname $out)"
|
||||
if ! $CC $CFLAGS -o "$out" "$src" "${OUT}/lib/${LIB_NAME}.o" "-L${OUT}/lib" "-l${LIB_NAME}" ${LDFLAGS}; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
recipe_docs
|
||||
}
|
||||
|
||||
recipe_examples() {
|
||||
for src in $(find "${EXAMPLES}" -name '*.c'); do
|
||||
out=$(basename "$src" .c)
|
||||
out="${OUT}/bin/$out"
|
||||
|
||||
if [ $(mod_time "$src") -ge $(mod_time "$out") ]; then
|
||||
echo "CC $(basename $out)"
|
||||
mkdir -p "$(dirname $out)"
|
||||
if ! $CC $CFLAGS -o "$out" "$src" "${OUT}/lib/${LIB_NAME}.o" "-L${OUT}/lib" "-l${LIB_NAME}" ${LDFLAGS}; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
recipe_clean() {
|
||||
rm -r "${BUILD}" "${OUT}"
|
||||
}
|
||||
|
||||
# Update copyright comments in sources and header files.
|
||||
recipe_license() {
|
||||
find . -name '*.[ch]' | while IFS= read -r src; do
|
||||
if [ -t 1 ]; then
|
||||
printf "LICENSE %s%*c\r" $(basename "$src") "16" " "
|
||||
fi
|
||||
srcHeader=$(grep -n -m 1 '^ \*/' "$src" | cut -d ':' -f 1)
|
||||
head "-n$srcHeader" "$src" |
|
||||
diff -u -p - "${LICENSE}" |
|
||||
patch "$src" | grep -v "^Hmm"
|
||||
done
|
||||
if [ -t 1 ]; then
|
||||
printf "%*c\n" "50" " "
|
||||
fi
|
||||
}
|
||||
|
||||
# Format source code files by running indent(1) on them.
|
||||
recipe_format() {
|
||||
find . -name '*.c' | while IFS= read -r src; do
|
||||
if [ -t 1 ]; then
|
||||
printf "FMT %s%*c\r" $(basename "$src") "16" " "
|
||||
fi
|
||||
if indent "$src"; then
|
||||
rm $(basename "$src").BAK
|
||||
fi
|
||||
done
|
||||
if [ -t 1 ]; then
|
||||
printf "%*c\n" "50" " "
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate a release tarball, checksum and sign it, and push it to
|
||||
# the web root.
|
||||
recipe_release() {
|
||||
# Tag the release at this point in time.
|
||||
cvs tag "$CVS_TAG"
|
||||
|
||||
mkdir -p "${OUT}/release"
|
||||
cd "${OUT}/release"
|
||||
|
||||
# Generate the release tarball.
|
||||
cvs export "-r$CVS_TAG" "${NAME}"
|
||||
mv "${NAME}" "${NAME}-v${VERSION}"
|
||||
tar -czf "${NAME}-v${VERSION}.tar.gz" "${NAME}-v${VERSION}"
|
||||
rm -r "${NAME}-v${VERSION}"
|
||||
|
||||
# Checksum the release tarball.
|
||||
sha256 "${NAME}-v${VERSION}.tar.gz" > "${NAME}-v${VERSION}.tar.gz.sha256"
|
||||
|
||||
# Sign the release tarball.
|
||||
if [ ! -z "${SIGNIFY_SECRET}" ]; then
|
||||
signify -S -s "${SIGNIFY_SECRET}" \
|
||||
-m "${NAME}-v${VERSION}.tar.gz" \
|
||||
-x "${NAME}-v${VERSION}.tar.gz.sig"
|
||||
else
|
||||
echo "Warning: SIGNIFY_SECRET not net."
|
||||
echo "The built tarball will not be signed."
|
||||
fi
|
||||
}
|
||||
|
||||
recipe_patch() {
|
||||
# If the user has not set their MXID, try to deduce one from
|
||||
# their system.
|
||||
if [ -z "$MXID" ]; then
|
||||
MXID="@${USER}:$(hostname)"
|
||||
fi
|
||||
|
||||
# If the user has not set their EDITOR, use a safe default.
|
||||
# (vi should be available on any POSIX system)
|
||||
if [ -z "$EDITOR" ]; then
|
||||
EDITOR=vi
|
||||
fi
|
||||
|
||||
NORMALIZED_MXID=$(echo "$MXID" | sed -e 's/@//g' -e 's/:/-/g')
|
||||
PATCH_FILE="${NORMALIZED_MXID}_$(date +%s).patch"
|
||||
|
||||
# Generate the actual patch file
|
||||
# Here we write some nice headers, and then do a cvs diff.
|
||||
(
|
||||
printf 'From: "%s" <%s>\n' "$DISPLAY_NAME" "$MXID"
|
||||
echo "Date: $(date)"
|
||||
echo "Subject: "
|
||||
echo
|
||||
cvs -q diff -uNp $PATCHSET | grep -v '^\? '
|
||||
) >"$PATCH_FILE"
|
||||
|
||||
"$EDITOR" "$PATCH_FILE"
|
||||
echo "$PATCH_FILE"
|
||||
}
|
||||
|
||||
recipe_diff() {
|
||||
tmp_patch="/tmp/${NAME}-$(date +%s).patch"
|
||||
cvs -q diff -uNp $PATCHSET >"$tmp_patch"
|
||||
if [ -z "$PAGER" ]; then
|
||||
PAGER="less -F"
|
||||
fi
|
||||
|
||||
$PAGER "$tmp_patch"
|
||||
rm "$tmp_patch"
|
||||
}
|
||||
|
||||
# Execute the user-specified recipes.
|
||||
for recipe in $@; do
|
||||
recipe_$recipe
|
||||
done
|
||||
|
||||
# If no recipe was provided, run a build.
|
||||
if [ -z "$1" ]; then
|
||||
recipe_build
|
||||
fi
|
|
@ -1,51 +0,0 @@
|
|||
.Dd $Mdocdate: May 21 2023 $
|
||||
.Dt HDOC 1
|
||||
.Os Cytoplasm
|
||||
.Sh NAME
|
||||
.Nm hdoc
|
||||
.Nd Generate documentation from a C header file.
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl i Ar file
|
||||
.Op Fl o Ar file
|
||||
.Op Fl D Ar key=value
|
||||
.Sh DESCRIPTION
|
||||
.Nm
|
||||
is an extremely simple documentation generator that generates
|
||||
a BSD man page from a specially-formatted C header file.
|
||||
See
|
||||
.Xr hdoc 5
|
||||
for details on the format of this header file.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl i Ar file
|
||||
The input C header file to read from. If this option is omitted,
|
||||
then the standard input is read.
|
||||
.It Fl o Ar file
|
||||
The output BSD man page file to write. If this option is omitted,
|
||||
then the standard output is written.
|
||||
.It Fl D Ar key=value
|
||||
Set the register
|
||||
.Ar key
|
||||
to
|
||||
.Ar value .
|
||||
.Nm
|
||||
registers are used in various places, and can be set in either
|
||||
the header file, or on the command line. Setting registers that
|
||||
should be the same in all headers is best done from the command
|
||||
line for maintainability purposes, but header-specific values
|
||||
should be set in the header file itself.
|
||||
.Pp
|
||||
Registers are explained in more detail in
|
||||
.Xr hdoc 5 .
|
||||
.El
|
||||
.Sh RETURN VALUE
|
||||
.Pp
|
||||
.Nm
|
||||
returns a success value if the header is well-formed and the
|
||||
man page is successfully generated. It returns an error code in
|
||||
all other scenarios.
|
||||
.Sh SEE ALSO
|
||||
.Xr hdoc 5 ,
|
||||
.Xr HeaderParser 3
|
|
@ -1,195 +0,0 @@
|
|||
.Dd $Mdocdate: May 21 2023 $
|
||||
.Dt HDOC 5
|
||||
.Os Cytoplasm
|
||||
.Sh NAME
|
||||
.Nm hdoc
|
||||
.Nd C header file format accepted by the documentation generator.
|
||||
.Sh DESCRIPTION
|
||||
.Pp
|
||||
.Nm
|
||||
uses an extremely primitive parser to generate documentation from
|
||||
C header files. As such, the format accepted by
|
||||
.Nm
|
||||
is rather strict and may not be suitable for other projects beyond
|
||||
of Cytoplasm. This document describes what
|
||||
.Nm
|
||||
considers to be a valid C header file, and how that header file can
|
||||
be annotated to produce a nicely-formatted man page.
|
||||
.Pp
|
||||
At the very top level, a C header is a sequences of tokens that
|
||||
represent the following:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
An ANSI C89 comment.
|
||||
.It
|
||||
A preprocessor directive.
|
||||
.It
|
||||
A typedef declaration.
|
||||
.It
|
||||
A constant or other global variable declaration.
|
||||
.It
|
||||
A function declaration.
|
||||
.El
|
||||
.Pp
|
||||
Note that global variables and functions
|
||||
.Em must
|
||||
be marked with
|
||||
.Ar extern ,
|
||||
otherwise the parser will fail to recognize them. This is by
|
||||
design; a header should make everything extern by default,
|
||||
because it does not actually implement or declare anything.
|
||||
.Pp
|
||||
Preprocessor directives are completely ignored. Regular C
|
||||
comments are also ignored.
|
||||
.Nm
|
||||
is primarily concerned with type declarations, global
|
||||
variables, and functions. It also inspects specially-formatted
|
||||
C comments, which are used to annotate these elements of the
|
||||
header. The format of these comments is described here.
|
||||
.Pp
|
||||
There are two types of special comments recognized, the first
|
||||
of which is called the ``main'' comment block, as it documents
|
||||
the header itself, not the declarations contained in it. Main
|
||||
comment blocks also control the behavior of the parser and the
|
||||
resulting man page by setting registers. The format of the
|
||||
main comment block, which typically appears only once at the
|
||||
top of the header, although this is not a requirement, is as
|
||||
follows:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
The comment should start with a ``triple star,'' like this:
|
||||
.Bd -literal -offset indent
|
||||
/***
|
||||
*
|
||||
*/
|
||||
.Ed
|
||||
.It
|
||||
Any lines that start with a ``@'' are parser directives that
|
||||
set registers. The name of the register to set follows
|
||||
immediately after the ``@'' sigil, and continues until the first
|
||||
whitespace. The rest of the line is the value of the register.
|
||||
A list of registers recognized by
|
||||
.Nm
|
||||
is as follows. These registers control the man page output,
|
||||
and the last value set is the one that is used:
|
||||
.Bl -tag -width Ds
|
||||
.It \&Nm
|
||||
The name register. The name of the man page will be set to the
|
||||
contents of this register. It defaults to ``Unnmamed.''
|
||||
.It \&Dd
|
||||
The date register. The date of the man page will be set to the
|
||||
contents of this register. If left unset, it defaults to the
|
||||
current date.
|
||||
.It \&Os
|
||||
The operating system register. The Os value, which appears in
|
||||
the bottom left and right corners of the man page, will be set
|
||||
to the contents of this register. If left unset, it is not
|
||||
output.
|
||||
.It \&Nd
|
||||
The description register. The description of the man page will
|
||||
be set to the contents of this register. It defaults to
|
||||
``No description.''
|
||||
.It \&Xr
|
||||
The cross reference register. The SEE ALSO section of the man
|
||||
page will list the specified cross references, which are to be
|
||||
separated by a single space. The section shall be omitted,
|
||||
because it is set automatically to the same section that the
|
||||
current man page will belong to. This limitation may be removed
|
||||
in the future.
|
||||
.El
|
||||
.Pp
|
||||
These registers control the parser itself, modifying its
|
||||
behavior as soon as the appear in the file:
|
||||
.Bl -tag -width Ds
|
||||
.It ignore-typedefs
|
||||
Don't throw an error for an undocumented type declaration.
|
||||
The value doesn't matter; as soon as this register shows
|
||||
up, it's set. In most cases, it should not be used, however,
|
||||
it may be helpful in a few scenarios, such as when there are
|
||||
multiple typedefs that do the same thing, but are controlled
|
||||
by preprocessor macros.
|
||||
.It suppress-warnings
|
||||
Don't issue a warning for invalid or unrecognized top-level
|
||||
tokens. They will instead be ignored until the next
|
||||
recognized top-level token is found. The value doesn't
|
||||
matter; as soon as this register shows up, it is set. In most
|
||||
cases, it should not be used, however it may be helpful in a
|
||||
few scenarios, such as when function declarations are generated
|
||||
by preprocessor directives and thus don't follow the standard
|
||||
form.
|
||||
.El
|
||||
.It
|
||||
Any other lines in the main block are output to the DESCRIPTION
|
||||
section of the main page. This description may contain mdoc
|
||||
directives in it, as the lines are copied verbatim. If multiple
|
||||
main comment blocks appear in a single header, their description
|
||||
lines are appended in the order they appear.
|
||||
.El
|
||||
.Pp
|
||||
Declaration documentation comments are created as follows:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
The comment should start with a ``double star,'' like this:
|
||||
.Bd -literal -offset indent
|
||||
/**
|
||||
*
|
||||
*/
|
||||
.Ed
|
||||
.It
|
||||
The contents of the comment are copied verbatim into the output,
|
||||
so the comment may contain mdoc directives.
|
||||
.It
|
||||
The comment must appear before a declaration. If multiple
|
||||
documentation comments appear before a declaration, the last
|
||||
one before the declaration is used.
|
||||
.El
|
||||
.Pp
|
||||
The generated man page includes the name and description of the
|
||||
header, a synopsis section that lists all of the functions in
|
||||
the header, a description section that contains all the non-register
|
||||
lines of the main comment blocks, and then all of the documentation
|
||||
for each function, with the function prototype displayed as a
|
||||
subsection header, and the documentation displayed under it.
|
||||
.Sh EXAMPLES
|
||||
.Pp
|
||||
Consider the following simple C header:
|
||||
.Bd -literal -offset indent
|
||||
#include <stdio.h>
|
||||
|
||||
extern void SayHello(FILE *);
|
||||
.Ed
|
||||
.Pp
|
||||
To annotate this header in the manner
|
||||
.Nm
|
||||
expects, do something like this:
|
||||
.Bd -literal -offset indent
|
||||
/***
|
||||
* @Nm Hello
|
||||
* @Nd Say hello.
|
||||
* @Dd May 17 2023
|
||||
*
|
||||
* .Nm
|
||||
* provides functionality to write hello world messages
|
||||
* into standard C file descriptors.
|
||||
*
|
||||
* @Xr fputs fprintf
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
/**
|
||||
* This function writes "hello world" to the given file
|
||||
* descriptor.
|
||||
* .Pp
|
||||
* There really isn't much more to be said about it.
|
||||
*/
|
||||
extern void SayHello(FILE *);
|
||||
.Ed
|
||||
.Pp
|
||||
This example shows how mdoc directives can be placed in
|
||||
documentation comments. Note that the triple-star comment
|
||||
documents the header itself, and the double-star comment
|
||||
documents the type declaration or function definition
|
||||
below it.
|
||||
.Sh SEE ALSO
|
||||
.Xr hdoc 5 ,
|
||||
.Xr HeaderParser 3
|
|
@ -1,118 +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 <Args.h>
|
||||
|
||||
#include <Memory.h>
|
||||
#include <Log.h>
|
||||
#include <Str.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
ArgParseStateInit(ArgParseState * state)
|
||||
{
|
||||
state->optPos = 1;
|
||||
state->optErr = 1;
|
||||
state->optInd = 1;
|
||||
state->optOpt = 0;
|
||||
state->optArg = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
ArgParse(ArgParseState * state, Array * args, const char *optStr)
|
||||
{
|
||||
const char *arg;
|
||||
|
||||
arg = ArrayGet(args, state->optInd);
|
||||
|
||||
if (arg && StrEquals(arg, "--"))
|
||||
{
|
||||
state->optInd++;
|
||||
return -1;
|
||||
}
|
||||
else if (!arg || arg[0] != '-' || !isalnum((unsigned char) arg[1]))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *opt = strchr(optStr, arg[state->optPos]);
|
||||
|
||||
state->optOpt = arg[state->optPos];
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
if (state->optErr && *optStr != ':')
|
||||
{
|
||||
Log(LOG_ERR, "Illegal option: %c", ArrayGet(args, 0), state->optOpt);
|
||||
}
|
||||
if (!arg[++state->optPos])
|
||||
{
|
||||
state->optInd++;
|
||||
state->optPos = 1;
|
||||
}
|
||||
return '?';
|
||||
}
|
||||
else if (opt[1] == ':')
|
||||
{
|
||||
if (arg[state->optPos + 1])
|
||||
{
|
||||
state->optArg = (char *) arg + state->optPos + 1;
|
||||
state->optInd++;
|
||||
state->optPos = 1;
|
||||
return state->optOpt;
|
||||
}
|
||||
else if (ArrayGet(args, state->optInd + 1))
|
||||
{
|
||||
state->optArg = (char *) ArrayGet(args, state->optInd + 1);
|
||||
state->optInd += 2;
|
||||
state->optPos = 1;
|
||||
return state->optOpt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state->optErr && *optStr != ':')
|
||||
{
|
||||
Log(LOG_ERR, "Option requires an argument: %c", state->optOpt);
|
||||
}
|
||||
if (!arg[++state->optPos])
|
||||
{
|
||||
state->optInd++;
|
||||
state->optPos = 1;
|
||||
}
|
||||
return *optStr == ':' ? ':' : '?';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!arg[++state->optPos])
|
||||
{
|
||||
state->optInd++;
|
||||
state->optPos = 1;
|
||||
}
|
||||
return state->optOpt;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,339 +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 <Array.h>
|
||||
|
||||
#ifndef ARRAY_BLOCK
|
||||
#define ARRAY_BLOCK 16
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <Memory.h>
|
||||
|
||||
struct Array
|
||||
{
|
||||
void **entries; /* An array of void pointers, to
|
||||
* store any data */
|
||||
size_t allocated; /* Elements allocated on the heap */
|
||||
size_t size; /* Elements actually filled */
|
||||
};
|
||||
|
||||
int
|
||||
ArrayAdd(Array * array, void *value)
|
||||
{
|
||||
if (!array)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ArrayInsert(array, array->size, value);
|
||||
}
|
||||
|
||||
Array *
|
||||
ArrayCreate(void)
|
||||
{
|
||||
Array *array = Malloc(sizeof(Array));
|
||||
|
||||
if (!array)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
array->size = 0;
|
||||
array->allocated = ARRAY_BLOCK;
|
||||
array->entries = Malloc(sizeof(void *) * ARRAY_BLOCK);
|
||||
|
||||
if (!array->entries)
|
||||
{
|
||||
Free(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
void *
|
||||
ArrayDelete(Array * array, size_t index)
|
||||
{
|
||||
size_t i;
|
||||
void *element;
|
||||
|
||||
if (!array || array->size <= index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
element = array->entries[index];
|
||||
|
||||
for (i = index; i < array->size - 1; i++)
|
||||
{
|
||||
array->entries[i] = array->entries[i + 1];
|
||||
}
|
||||
|
||||
array->size--;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
void
|
||||
ArrayFree(Array * array)
|
||||
{
|
||||
if (array)
|
||||
{
|
||||
Free(array->entries);
|
||||
Free(array);
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
ArrayGet(Array * array, size_t index)
|
||||
{
|
||||
if (!array)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= array->size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return array->entries[index];
|
||||
}
|
||||
|
||||
|
||||
extern int
|
||||
ArrayInsert(Array * array, size_t index, void *value)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (!array || !value || index > array->size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (array->size >= array->allocated)
|
||||
{
|
||||
void **tmp;
|
||||
size_t newSize = array->allocated + ARRAY_BLOCK;
|
||||
|
||||
tmp = array->entries;
|
||||
|
||||
array->entries = Realloc(array->entries,
|
||||
sizeof(void *) * newSize);
|
||||
|
||||