C99 Compliance (#29)
Some checks failed
Compile Cytoplasm / Compile Cytoplasm (x86_64, freebsd-v14.0) (push) Failing after 8s
Compile Cytoplasm / Compile Cytoplasm (x86, freebsd-v14.0) (push) Failing after 10s
Compile Cytoplasm / Compile Cytoplasm (x86_64, alpine-v3.19) (push) Successful in 9s
Compile Cytoplasm / Compile Cytoplasm (x86, debian-v12.4) (push) Successful in 13s
Compile Cytoplasm / Compile Cytoplasm (x86, alpine-v3.19) (push) Successful in 11s
Compile Cytoplasm / Compile Cytoplasm (x86_64, debian-v12.4) (push) Successful in 14s
Compile Cytoplasm / Compile Cytoplasm (x86_64, netbsd-v9.3) (push) Successful in 15s
Compile Cytoplasm / Compile Cytoplasm (x86, netbsd-v9.3) (push) Successful in 15s
Compile Cytoplasm / Compile Cytoplasm (x86_64, openbsd-v7.4) (push) Successful in 17s
Some checks failed
Compile Cytoplasm / Compile Cytoplasm (x86_64, freebsd-v14.0) (push) Failing after 8s
Compile Cytoplasm / Compile Cytoplasm (x86, freebsd-v14.0) (push) Failing after 10s
Compile Cytoplasm / Compile Cytoplasm (x86_64, alpine-v3.19) (push) Successful in 9s
Compile Cytoplasm / Compile Cytoplasm (x86, debian-v12.4) (push) Successful in 13s
Compile Cytoplasm / Compile Cytoplasm (x86, alpine-v3.19) (push) Successful in 11s
Compile Cytoplasm / Compile Cytoplasm (x86_64, debian-v12.4) (push) Successful in 14s
Compile Cytoplasm / Compile Cytoplasm (x86_64, netbsd-v9.3) (push) Successful in 15s
Compile Cytoplasm / Compile Cytoplasm (x86, netbsd-v9.3) (push) Successful in 15s
Compile Cytoplasm / Compile Cytoplasm (x86_64, openbsd-v7.4) (push) Successful in 17s
This pull request brings Cytoplasm up from C89 to C99, which makes it much more portable across platforms. In particular, this pull request solves a number of issues with 32-bit platforms. Closes #28. Closes #12. Closes #20. Reviewed-on: #29
This commit is contained in:
parent
d0969d0dd7
commit
662696ce12
40 changed files with 384 additions and 1667 deletions
94
configure
vendored
94
configure
vendored
|
@ -13,23 +13,44 @@ SRC="src"
|
||||||
INCLUDE="src/include"
|
INCLUDE="src/include"
|
||||||
TOOLS="tools"
|
TOOLS="tools"
|
||||||
|
|
||||||
CFLAGS="-Wall -Wextra -pedantic -std=c89 -O3 -pipe -D_DEFAULT_SOURCE -I${INCLUDE}"
|
# Default compiler flags. These must be supported by all POSIX C compilers.
|
||||||
LIBS="-lm -pthread"
|
# "Fancy" compilers that have additional options must be detected and set below.
|
||||||
|
CFLAGS="-O1 -D_DEFAULT_SOURCE -I${INCLUDE}"
|
||||||
|
LIBS="-lm -lpthread"
|
||||||
|
|
||||||
|
# Default args for all platforms.
|
||||||
|
SCRIPT_ARGS="--prefix=/usr/local --lib-name=Cytoplasm"
|
||||||
|
|
||||||
# Set default args for all platforms
|
# Set SSL flags depending on the platform.
|
||||||
SCRIPT_ARGS="--cc=cc --prefix=/usr/local --enable-ld-extra --lib-name=Cytoplasm --lib-version=0.4.1 $@"
|
|
||||||
|
|
||||||
# Set platform specific args
|
|
||||||
case "$(uname)" in
|
case "$(uname)" in
|
||||||
OpenBSD)
|
OpenBSD)
|
||||||
SCRIPT_ARGS="--with-libressl $SCRIPT_ARGS"
|
SCRIPT_ARGS="${SCRIPT_ARGS} --with-libressl"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
SCRIPT_ARGS="--with-openssl $SCRIPT_ARGS"
|
SCRIPT_ARGS="${SCRIPT_ARGS} --with-openssl"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# Set compiler depending on the platform.
|
||||||
|
case "$(uname)" in
|
||||||
|
Linux|NetBSD)
|
||||||
|
# These systems typically use GCC.
|
||||||
|
SCRIPT_ARGS="${SCRIPT_ARGS} --cc=gcc"
|
||||||
|
;;
|
||||||
|
OpenBSD|FreeBSD)
|
||||||
|
# These systems typically use Clang.
|
||||||
|
SCRIPT_ARGS="${SCRIPT_ARGS} --cc=clang"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Use default compiler which is required to be present on
|
||||||
|
# all POSIX-compliant systems.
|
||||||
|
SCRIPT_ARGS="${SCRIPT_ARGS} --cc=c99"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Append any additional args specified by user
|
||||||
|
SCRIPT_ARGS="${SCRIPT_ARGS} $@"
|
||||||
|
|
||||||
echo "Processing options..."
|
echo "Processing options..."
|
||||||
echo "Ran with arguments: $SCRIPT_ARGS"
|
echo "Ran with arguments: $SCRIPT_ARGS"
|
||||||
|
|
||||||
|
@ -38,6 +59,14 @@ for arg in $SCRIPT_ARGS; do
|
||||||
case "$arg" in
|
case "$arg" in
|
||||||
--cc=*)
|
--cc=*)
|
||||||
CC=$(echo "$arg" | cut -d '=' -f 2-)
|
CC=$(echo "$arg" | cut -d '=' -f 2-)
|
||||||
|
case "${CC}" in
|
||||||
|
gcc*|clang*)
|
||||||
|
# "Fancy" compilers that support a plethora of additional flags we
|
||||||
|
# want to enable if present.
|
||||||
|
CFLAGS="-Wall -Werror -pedantic -std=c99 ${CFLAGS}"
|
||||||
|
LDFLAGS="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
;;
|
;;
|
||||||
--with-openssl)
|
--with-openssl)
|
||||||
TLS_IMPL="TLS_OPENSSL"
|
TLS_IMPL="TLS_OPENSSL"
|
||||||
|
@ -54,35 +83,15 @@ for arg in $SCRIPT_ARGS; do
|
||||||
--prefix=*)
|
--prefix=*)
|
||||||
PREFIX=$(echo "$arg" | cut -d '=' -f 2-)
|
PREFIX=$(echo "$arg" | cut -d '=' -f 2-)
|
||||||
;;
|
;;
|
||||||
--enable-ld-extra)
|
|
||||||
LD_EXTRA="-flto -fdata-sections -ffunction-sections -s -Wl,-gc-sections"
|
|
||||||
;;
|
|
||||||
--disable-ld-extra)
|
|
||||||
LD_EXTRA=""
|
|
||||||
;;
|
|
||||||
--lib-name=*)
|
--lib-name=*)
|
||||||
LIB_NAME=$(echo "$arg" | cut -d '=' -f 2-)
|
LIB_NAME=$(echo "$arg" | cut -d '=' -f 2-)
|
||||||
;;
|
;;
|
||||||
--lib-version=*)
|
|
||||||
LIB_VERSION=$(echo "$arg" | cut -d '=' -f 2-)
|
|
||||||
;;
|
|
||||||
--enable-debug)
|
--enable-debug)
|
||||||
DEBUG="-O0 -g"
|
DEBUG="-O0 -g"
|
||||||
echo "Notice: --enable-debug implies --disable-ld-extra and --no-static."
|
|
||||||
echo "You must explicitly provide --enable-ld-extra and/or --static after"
|
|
||||||
echo "specifying --enable-debug if you wish to enable these features in debug mode."
|
|
||||||
LD_EXTRA=""
|
|
||||||
STATIC=""
|
|
||||||
;;
|
;;
|
||||||
--disable-debug)
|
--disable-debug)
|
||||||
DEBUG=""
|
DEBUG=""
|
||||||
;;
|
;;
|
||||||
--static)
|
|
||||||
STATIC="-static -Wl,-static"
|
|
||||||
;;
|
|
||||||
--no-static)
|
|
||||||
STATIC=""
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
echo "Invalid argument: $arg"
|
echo "Invalid argument: $arg"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -95,8 +104,8 @@ if [ -n "$TLS_IMPL" ]; then
|
||||||
LIBS="${LIBS} ${TLS_LIBS}"
|
LIBS="${LIBS} ${TLS_LIBS}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
CFLAGS="${CFLAGS} '-DLIB_NAME=\"${LIB_NAME}\"' '-DLIB_VERSION=\"${LIB_VERSION}\"' ${DEBUG}"
|
CFLAGS="${CFLAGS} '-DLIB_NAME=\"${LIB_NAME}\"' ${DEBUG}"
|
||||||
LDFLAGS="${LIBS} ${LD_EXTRA}"
|
LDFLAGS="${LIBS} ${LDFLAGS}"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Makefile generation
|
# Makefile generation
|
||||||
|
@ -128,11 +137,27 @@ print_obj() {
|
||||||
printf '%s ' "$2"
|
printf '%s ' "$2"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_deps() {
|
||||||
|
src="$1"
|
||||||
|
|
||||||
|
${CC} -I${INCLUDE} -E "$src" \
|
||||||
|
| grep '^#' \
|
||||||
|
| awk '{print $3}' \
|
||||||
|
| cut -d '"' -f 2 \
|
||||||
|
| sort \
|
||||||
|
| uniq \
|
||||||
|
| grep -v '^[/<]' \
|
||||||
|
| grep "^${SRC}/" \
|
||||||
|
| while IFS= read -r dep; do
|
||||||
|
printf "%s " "$dep"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
compile_obj() {
|
compile_obj() {
|
||||||
src="$1"
|
src="$1"
|
||||||
obj="$2"
|
obj="$2"
|
||||||
|
|
||||||
${CC} -I${INCLUDE} -MM -MT "${obj}" "${src}"
|
echo "${obj}: $(get_deps ${src})"
|
||||||
echo "${TAB}@mkdir -p $(dirname ${obj})"
|
echo "${TAB}@mkdir -p $(dirname ${obj})"
|
||||||
echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\""
|
echo "${TAB}\$(CC) \$(CFLAGS) -fPIC -c -o \"${obj}\" \"${src}\""
|
||||||
}
|
}
|
||||||
|
@ -143,16 +168,13 @@ compile_bin() {
|
||||||
|
|
||||||
echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${src}"
|
echo "${out}: ${OUT}/lib/lib${LIB_NAME}.a ${OUT}/lib/lib${LIB_NAME}.so ${src}"
|
||||||
echo "${TAB}@mkdir -p ${OUT}/bin"
|
echo "${TAB}@mkdir -p ${OUT}/bin"
|
||||||
echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME} ${STATIC}"
|
echo "${TAB}\$(CC) \$(CFLAGS) -o \"${out}\" \"${src}\" -L${OUT}/lib \$(LDFLAGS) -l${LIB_NAME}"
|
||||||
}
|
}
|
||||||
|
|
||||||
compile_doc() {
|
compile_doc() {
|
||||||
src="$1"
|
src="$1"
|
||||||
out="$2"
|
out="$2"
|
||||||
|
pref="LD_LIBRARY_PATH=${OUT}/lib "
|
||||||
if [ -z "${STATIC}" ]; then
|
|
||||||
pref="LD_LIBRARY_PATH=${OUT}/lib "
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "${out}: ${OUT}/bin/hdoc ${src}"
|
echo "${out}: ${OUT}/bin/hdoc ${src}"
|
||||||
echo "${TAB}@mkdir -p ${OUT}/man/man3"
|
echo "${TAB}@mkdir -p ${OUT}/man/man3"
|
||||||
|
|
20
src/Array.c
20
src/Array.c
|
@ -38,12 +38,12 @@ struct Array
|
||||||
size_t size; /* Elements actually filled */
|
size_t size; /* Elements actually filled */
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
bool
|
||||||
ArrayAdd(Array * array, void *value)
|
ArrayAdd(Array * array, void *value)
|
||||||
{
|
{
|
||||||
if (!array)
|
if (!array)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ArrayInsert(array, array->size, value);
|
return ArrayInsert(array, array->size, value);
|
||||||
|
@ -122,14 +122,14 @@ ArrayGet(Array * array, size_t index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern int
|
bool
|
||||||
ArrayInsert(Array * array, size_t index, void *value)
|
ArrayInsert(Array * array, size_t index, void *value)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!array || !value || index > array->size)
|
if (!array || !value || index > array->size)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array->size >= array->allocated)
|
if (array->size >= array->allocated)
|
||||||
|
@ -145,7 +145,7 @@ ArrayInsert(Array * array, size_t index, void *value)
|
||||||
if (!array->entries)
|
if (!array->entries)
|
||||||
{
|
{
|
||||||
array->entries = tmp;
|
array->entries = tmp;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
array->allocated = newSize;
|
array->allocated = newSize;
|
||||||
|
@ -160,7 +160,7 @@ ArrayInsert(Array * array, size_t index, void *value)
|
||||||
|
|
||||||
array->entries[index] = value;
|
array->entries[index] = value;
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *
|
extern void *
|
||||||
|
@ -200,14 +200,14 @@ ArraySize(Array * array)
|
||||||
return array->size;
|
return array->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
ArrayTrim(Array * array)
|
ArrayTrim(Array * array)
|
||||||
{
|
{
|
||||||
void **tmp;
|
void **tmp;
|
||||||
|
|
||||||
if (!array)
|
if (!array)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = array->entries;
|
tmp = array->entries;
|
||||||
|
@ -218,10 +218,10 @@ ArrayTrim(Array * array)
|
||||||
if (!array->entries)
|
if (!array->entries)
|
||||||
{
|
{
|
||||||
array->entries = tmp;
|
array->entries = tmp;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -212,7 +212,7 @@ Base64Unpad(char *base64, size_t length)
|
||||||
base64[length] = '\0';
|
base64[length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int
|
bool
|
||||||
Base64Pad(char **base64Ptr, size_t length)
|
Base64Pad(char **base64Ptr, size_t length)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
@ -221,7 +221,7 @@ Base64Pad(char **base64Ptr, size_t length)
|
||||||
|
|
||||||
if (length % 4 == 0)
|
if (length % 4 == 0)
|
||||||
{
|
{
|
||||||
return length; /* Success: no padding needed */
|
return true; /* Success: no padding needed */
|
||||||
}
|
}
|
||||||
|
|
||||||
newSize = length + (4 - (length % 4));
|
newSize = length + (4 - (length % 4));
|
||||||
|
@ -229,7 +229,7 @@ Base64Pad(char **base64Ptr, size_t length)
|
||||||
tmp = Realloc(*base64Ptr, newSize + 100);;
|
tmp = Realloc(*base64Ptr, newSize + 100);;
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
{
|
{
|
||||||
return 0; /* Memory error */
|
return false; /* Memory error */
|
||||||
}
|
}
|
||||||
*base64Ptr = tmp;
|
*base64Ptr = tmp;
|
||||||
|
|
||||||
|
@ -240,5 +240,5 @@ Base64Pad(char **base64Ptr, size_t length)
|
||||||
|
|
||||||
(*base64Ptr)[newSize] = '\0';
|
(*base64Ptr)[newSize] = '\0';
|
||||||
|
|
||||||
return newSize;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
55
src/Cron.c
55
src/Cron.c
|
@ -23,32 +23,33 @@
|
||||||
*/
|
*/
|
||||||
#include <Cron.h>
|
#include <Cron.h>
|
||||||
|
|
||||||
#include <UInt64.h>
|
|
||||||
#include <Array.h>
|
#include <Array.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
struct Cron
|
struct Cron
|
||||||
{
|
{
|
||||||
UInt64 tick;
|
uint64_t tick;
|
||||||
Array *jobs;
|
Array *jobs;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
volatile unsigned int stop:1;
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
|
volatile bool stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Job
|
typedef struct Job
|
||||||
{
|
{
|
||||||
UInt64 interval;
|
uint64_t interval;
|
||||||
UInt64 lastExec;
|
uint64_t lastExec;
|
||||||
JobFunc *func;
|
JobFunc *func;
|
||||||
void *args;
|
void *args;
|
||||||
} Job;
|
} Job;
|
||||||
|
|
||||||
static Job *
|
static Job *
|
||||||
JobCreate(UInt32 interval, JobFunc * func, void *args)
|
JobCreate(uint64_t interval, JobFunc * func, void *args)
|
||||||
{
|
{
|
||||||
Job *job;
|
Job *job;
|
||||||
|
|
||||||
|
@ -63,8 +64,8 @@ JobCreate(UInt32 interval, JobFunc * func, void *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
job->interval = UInt64Create(0, interval);
|
job->interval = interval;
|
||||||
job->lastExec = UInt64Create(0, 0);
|
job->lastExec = 0;
|
||||||
job->func = func;
|
job->func = func;
|
||||||
job->args = args;
|
job->args = args;
|
||||||
|
|
||||||
|
@ -79,51 +80,51 @@ CronThread(void *args)
|
||||||
while (!cron->stop)
|
while (!cron->stop)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
UInt64 ts; /* tick start */
|
uint64_t ts; /* tick start */
|
||||||
UInt64 te; /* tick end */
|
uint64_t te; /* tick end */
|
||||||
|
|
||||||
pthread_mutex_lock(&cron->lock);
|
pthread_mutex_lock(&cron->lock);
|
||||||
|
|
||||||
ts = UtilServerTs();
|
ts = UtilTsMillis();
|
||||||
|
|
||||||
for (i = 0; i < ArraySize(cron->jobs); i++)
|
for (i = 0; i < ArraySize(cron->jobs); i++)
|
||||||
{
|
{
|
||||||
Job *job = ArrayGet(cron->jobs, i);
|
Job *job = ArrayGet(cron->jobs, i);
|
||||||
|
|
||||||
if (UInt64Gt(UInt64Sub(ts, job->lastExec), job->interval))
|
if ((ts - job->lastExec) > job->interval)
|
||||||
{
|
{
|
||||||
job->func(job->args);
|
job->func(job->args);
|
||||||
job->lastExec = ts;
|
job->lastExec = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UInt64Eq(job->interval, UInt64Create(0, 0)))
|
if (!job->interval)
|
||||||
{
|
{
|
||||||
ArrayDelete(cron->jobs, i);
|
ArrayDelete(cron->jobs, i);
|
||||||
Free(job);
|
Free(job);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
te = UtilServerTs();
|
te = UtilTsMillis();
|
||||||
|
|
||||||
pthread_mutex_unlock(&cron->lock);
|
pthread_mutex_unlock(&cron->lock);
|
||||||
|
|
||||||
/* Only sleep if the jobs didn't overrun the tick */
|
// Only sleep if the jobs didn't overrun the tick
|
||||||
if (UInt64Gt(cron->tick, UInt64Sub(te, ts)))
|
if (cron->tick > (te - ts))
|
||||||
{
|
{
|
||||||
const UInt64 microTick = UInt64Create(0, 100);
|
const uint64_t microTick = 100;
|
||||||
|
|
||||||
UInt64 remainingTick = UInt64Sub(cron->tick, UInt64Sub(te, ts));
|
uint64_t remainingTick = cron->tick - (te - ts);
|
||||||
|
|
||||||
/* Only sleep for microTick ms at a time because if the job
|
/* Only sleep for microTick ms at a time because if the job
|
||||||
* scheduler is supposed to stop before the tick is up, we
|
* scheduler is supposed to stop before the tick is up, we
|
||||||
* don't want to be stuck in a long sleep */
|
* don't want to be stuck in a long sleep */
|
||||||
while (UInt64Geq(remainingTick, microTick) && !cron->stop)
|
while (remainingTick >= microTick && !cron->stop)
|
||||||
{
|
{
|
||||||
UtilSleepMillis(microTick);
|
UtilSleepMillis(microTick);
|
||||||
|
|
||||||
remainingTick = UInt64Sub(remainingTick, microTick);
|
remainingTick -= microTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UInt64Neq(remainingTick, UInt64Create(0, 0)) && !cron->stop)
|
if (remainingTick && !cron->stop)
|
||||||
{
|
{
|
||||||
UtilSleepMillis(remainingTick);
|
UtilSleepMillis(remainingTick);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +135,7 @@ CronThread(void *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
Cron *
|
Cron *
|
||||||
CronCreate(UInt32 tick)
|
CronCreate(uint64_t tick)
|
||||||
{
|
{
|
||||||
Cron *cron = Malloc(sizeof(Cron));
|
Cron *cron = Malloc(sizeof(Cron));
|
||||||
|
|
||||||
|
@ -150,8 +151,8 @@ CronCreate(UInt32 tick)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cron->tick = UInt64Create(0, tick);
|
cron->tick = tick;
|
||||||
cron->stop = 1;
|
cron->stop = true;
|
||||||
|
|
||||||
pthread_mutex_init(&cron->lock, NULL);
|
pthread_mutex_init(&cron->lock, NULL);
|
||||||
|
|
||||||
|
@ -180,7 +181,7 @@ CronOnce(Cron * cron, JobFunc * func, void *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CronEvery(Cron * cron, unsigned long interval, JobFunc * func, void *args)
|
CronEvery(Cron * cron, uint64_t interval, JobFunc * func, void *args)
|
||||||
{
|
{
|
||||||
Job *job;
|
Job *job;
|
||||||
|
|
||||||
|
@ -208,7 +209,7 @@ CronStart(Cron * cron)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cron->stop = 0;
|
cron->stop = false;
|
||||||
|
|
||||||
pthread_create(&cron->thread, NULL, CronThread, cron);
|
pthread_create(&cron->thread, NULL, CronThread, cron);
|
||||||
}
|
}
|
||||||
|
@ -221,7 +222,7 @@ CronStop(Cron * cron)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cron->stop = 1;
|
cron->stop = true;
|
||||||
|
|
||||||
pthread_join(cron->thread, NULL);
|
pthread_join(cron->thread, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,22 @@
|
||||||
|
|
||||||
#include <Cytoplasm.h>
|
#include <Cytoplasm.h>
|
||||||
|
|
||||||
char *CytoplasmGetName()
|
int
|
||||||
|
CytoplasmGetVersion(void)
|
||||||
{
|
{
|
||||||
return LIB_NAME;
|
return CYTOPLASM_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *CytoplasmGetVersion()
|
const char *
|
||||||
|
CytoplasmGetVersionStr(void)
|
||||||
{
|
{
|
||||||
return LIB_VERSION;
|
return "v" STRINGIFY(CYTOPLASM_VERSION_MAJOR)
|
||||||
}
|
"." STRINGIFY(CYTOPLASM_VERSION_MINOR)
|
||||||
|
"." STRINGIFY(CYTOPLASM_VERSION_PATCH)
|
||||||
|
#if CYTOPLASM_VERSION_ALPHA
|
||||||
|
"-alpha" STRINGIFY(CYTOPLASM_VERSION_ALPHA)
|
||||||
|
#elif CYTOPLASM_VERSION_BETA
|
||||||
|
"-beta" STRINGIFY(CYTOPLASM_VERSION_BETA)
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
51
src/Db.c
51
src/Db.c
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
#include <Db.h>
|
#include <Db.h>
|
||||||
|
|
||||||
#include <UInt64.h>
|
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
@ -77,7 +76,7 @@ struct DbRef
|
||||||
{
|
{
|
||||||
HashMap *json;
|
HashMap *json;
|
||||||
|
|
||||||
UInt64 ts;
|
uint64_t ts;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
Array *name;
|
Array *name;
|
||||||
|
@ -495,12 +494,12 @@ DbLockFromArr(Db * db, Array * args)
|
||||||
|
|
||||||
if (ref) /* In cache */
|
if (ref) /* In cache */
|
||||||
{
|
{
|
||||||
UInt64 diskTs = UtilLastModified(file);
|
uint64_t diskTs = UtilLastModified(file);
|
||||||
|
|
||||||
ref->fd = fd;
|
ref->fd = fd;
|
||||||
ref->stream = stream;
|
ref->stream = stream;
|
||||||
|
|
||||||
if (UInt64Gt(diskTs, ref->ts))
|
if (diskTs > ref->ts)
|
||||||
{
|
{
|
||||||
/* File was modified on disk since it was cached */
|
/* File was modified on disk since it was cached */
|
||||||
HashMap *json = JsonDecode(ref->stream);
|
HashMap *json = JsonDecode(ref->stream);
|
||||||
|
@ -588,7 +587,7 @@ DbLockFromArr(Db * db, Array * args)
|
||||||
|
|
||||||
if (db->cache)
|
if (db->cache)
|
||||||
{
|
{
|
||||||
ref->ts = UtilServerTs();
|
ref->ts = UtilTsMillis();
|
||||||
ref->size = DbComputeSize(ref->json);
|
ref->size = DbComputeSize(ref->json);
|
||||||
HashMapSet(db->cache, hash, ref);
|
HashMapSet(db->cache, hash, ref);
|
||||||
db->cacheSize += ref->size;
|
db->cacheSize += ref->size;
|
||||||
|
@ -652,7 +651,7 @@ DbCreate(Db * db, size_t nArgs,...)
|
||||||
|
|
||||||
file = DbFileName(db, args);
|
file = DbFileName(db, args);
|
||||||
|
|
||||||
if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0)))
|
if (UtilLastModified(file))
|
||||||
{
|
{
|
||||||
Free(file);
|
Free(file);
|
||||||
ArrayFree(args);
|
ArrayFree(args);
|
||||||
|
@ -694,19 +693,19 @@ DbCreate(Db * db, size_t nArgs,...)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
DbDelete(Db * db, size_t nArgs,...)
|
DbDelete(Db * db, size_t nArgs,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
Array *args;
|
Array *args;
|
||||||
char *file;
|
char *file;
|
||||||
char *hash;
|
char *hash;
|
||||||
int ret = 1;
|
bool ret = true;
|
||||||
DbRef *ref;
|
DbRef *ref;
|
||||||
|
|
||||||
if (!db)
|
if (!db)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
va_start(ap, nArgs);
|
va_start(ap, nArgs);
|
||||||
|
@ -755,9 +754,9 @@ DbDelete(Db * db, size_t nArgs,...)
|
||||||
|
|
||||||
Free(hash);
|
Free(hash);
|
||||||
|
|
||||||
if (UInt64Neq(UtilLastModified(file), UInt64Create(0, 0)))
|
if (UtilLastModified(file))
|
||||||
{
|
{
|
||||||
ret = remove(file) == 0;
|
ret = (remove(file) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&db->lock);
|
pthread_mutex_unlock(&db->lock);
|
||||||
|
@ -790,14 +789,14 @@ DbLock(Db * db, size_t nArgs,...)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
DbUnlock(Db * db, DbRef * ref)
|
DbUnlock(Db * db, DbRef * ref)
|
||||||
{
|
{
|
||||||
int destroy;
|
bool destroy;
|
||||||
|
|
||||||
if (!db || !ref)
|
if (!db || !ref)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lseek(ref->fd, 0L, SEEK_SET);
|
lseek(ref->fd, 0L, SEEK_SET);
|
||||||
|
@ -806,7 +805,7 @@ DbUnlock(Db * db, DbRef * ref)
|
||||||
pthread_mutex_unlock(&db->lock);
|
pthread_mutex_unlock(&db->lock);
|
||||||
Log(LOG_ERR, "Failed to truncate file on disk.");
|
Log(LOG_ERR, "Failed to truncate file on disk.");
|
||||||
Log(LOG_ERR, "Error on fd %d: %s", ref->fd, strerror(errno));
|
Log(LOG_ERR, "Error on fd %d: %s", ref->fd, strerror(errno));
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonEncode(ref->json, ref->stream, JSON_DEFAULT);
|
JsonEncode(ref->json, ref->stream, JSON_DEFAULT);
|
||||||
|
@ -827,18 +826,18 @@ DbUnlock(Db * db, DbRef * ref)
|
||||||
* require some items to be evicted. */
|
* require some items to be evicted. */
|
||||||
DbCacheEvict(db);
|
DbCacheEvict(db);
|
||||||
|
|
||||||
destroy = 0;
|
destroy = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroy = 1;
|
destroy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Free(key);
|
Free(key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
destroy = 1;
|
destroy = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destroy)
|
if (destroy)
|
||||||
|
@ -850,16 +849,16 @@ DbUnlock(Db * db, DbRef * ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&db->lock);
|
pthread_mutex_unlock(&db->lock);
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
DbExists(Db * db, size_t nArgs,...)
|
DbExists(Db * db, size_t nArgs,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
Array *args;
|
Array *args;
|
||||||
char *file;
|
char *file;
|
||||||
int ret;
|
bool ret;
|
||||||
|
|
||||||
va_start(ap, nArgs);
|
va_start(ap, nArgs);
|
||||||
args = ArrayFromVarArgs(nArgs, ap);
|
args = ArrayFromVarArgs(nArgs, ap);
|
||||||
|
@ -867,13 +866,13 @@ DbExists(Db * db, size_t nArgs,...)
|
||||||
|
|
||||||
if (!args)
|
if (!args)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&db->lock);
|
pthread_mutex_lock(&db->lock);
|
||||||
|
|
||||||
file = DbFileName(db, args);
|
file = DbFileName(db, args);
|
||||||
ret = UInt64Neq(UtilLastModified(file), UInt64Create(0, 0));
|
ret = (UtilLastModified(file) != 0);
|
||||||
|
|
||||||
pthread_mutex_unlock(&db->lock);
|
pthread_mutex_unlock(&db->lock);
|
||||||
|
|
||||||
|
@ -955,15 +954,15 @@ DbJson(DbRef * ref)
|
||||||
return ref ? ref->json : NULL;
|
return ref ? ref->json : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
DbJsonSet(DbRef * ref, HashMap * json)
|
DbJsonSet(DbRef * ref, HashMap * json)
|
||||||
{
|
{
|
||||||
if (!ref || !json)
|
if (!ref || !json)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonFree(ref->json);
|
JsonFree(ref->json);
|
||||||
ref->json = JsonDuplicate(json);
|
ref->json = JsonDuplicate(json);
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,12 +247,12 @@ HashMapGet(HashMap * map, const char *key)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i)
|
HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i)
|
||||||
{
|
{
|
||||||
if (!map)
|
if (!map)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*i >= map->capacity)
|
if (*i >= map->capacity)
|
||||||
|
@ -260,7 +260,7 @@ HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i)
|
||||||
*i = 0;
|
*i = 0;
|
||||||
*key = NULL;
|
*key = NULL;
|
||||||
*value = NULL;
|
*value = NULL;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*i < map->capacity)
|
while (*i < map->capacity)
|
||||||
|
@ -273,20 +273,20 @@ HashMapIterateReentrant(HashMap * map, char **key, void **value, size_t * i)
|
||||||
{
|
{
|
||||||
*key = bucket->key;
|
*key = bucket->key;
|
||||||
*value = bucket->value;
|
*value = bucket->value;
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*i = 0;
|
*i = 0;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
HashMapIterate(HashMap * map, char **key, void **value)
|
HashMapIterate(HashMap * map, char **key, void **value)
|
||||||
{
|
{
|
||||||
if (!map)
|
if (!map)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <Cytoplasm.h>
|
||||||
#include <Http.h>
|
#include <Http.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
|
@ -154,7 +155,7 @@ HttpRequest(HttpRequestMethod method, int flags, unsigned short port, char *host
|
||||||
HttpRequestMethodToString(method), path);
|
HttpRequestMethodToString(method), path);
|
||||||
|
|
||||||
HttpRequestHeader(context, "Connection", "close");
|
HttpRequestHeader(context, "Connection", "close");
|
||||||
HttpRequestHeader(context, "User-Agent", LIB_NAME "/" LIB_VERSION);
|
HttpRequestHeader(context, "User-Agent", LIB_NAME "/" STRINGIFY(CYTOPLASM_VERSION));
|
||||||
HttpRequestHeader(context, "Host", host);
|
HttpRequestHeader(context, "Host", host);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
|
|
|
@ -143,7 +143,7 @@ HttpRouterFree(HttpRouter * router)
|
||||||
Free(router);
|
Free(router);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec)
|
HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec)
|
||||||
{
|
{
|
||||||
RouteNode *node;
|
RouteNode *node;
|
||||||
|
@ -152,19 +152,19 @@ HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec)
|
||||||
|
|
||||||
if (!router || !regPath || !exec)
|
if (!router || !regPath || !exec)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StrEquals(regPath, "/"))
|
if (StrEquals(regPath, "/"))
|
||||||
{
|
{
|
||||||
router->root->exec = exec;
|
router->root->exec = exec;
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
regPath = StrDuplicate(regPath);
|
regPath = StrDuplicate(regPath);
|
||||||
if (!regPath)
|
if (!regPath)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = regPath;
|
tmp = regPath;
|
||||||
|
@ -187,10 +187,10 @@ HttpRouterAdd(HttpRouter * router, char *regPath, HttpRouteFunc * exec)
|
||||||
|
|
||||||
Free(regPath);
|
Free(regPath);
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
{
|
{
|
||||||
RouteNode *node;
|
RouteNode *node;
|
||||||
|
@ -199,17 +199,17 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
HttpRouteFunc *exec = NULL;
|
HttpRouteFunc *exec = NULL;
|
||||||
Array *matches = NULL;
|
Array *matches = NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
int retval;
|
bool retval;
|
||||||
|
|
||||||
if (!router || !path)
|
if (!router || !path)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
matches = ArrayCreate();
|
matches = ArrayCreate();
|
||||||
if (!matches)
|
if (!matches)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
node = router->root;
|
node = router->root;
|
||||||
|
@ -280,7 +280,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
|
|
||||||
if (!exec)
|
if (!exec)
|
||||||
{
|
{
|
||||||
retval = 0;
|
retval = false;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ HttpRouterRoute(HttpRouter * router, char *path, void *args, void **ret)
|
||||||
exec(matches, args);
|
exec(matches, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
retval = 1;
|
retval = true;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
for (i = 0; i < ArraySize(matches); i++)
|
for (i = 0; i < ArraySize(matches); i++)
|
||||||
|
|
|
@ -465,7 +465,7 @@ HttpServerWorkerThread(void *args)
|
||||||
ssize_t i = 0;
|
ssize_t i = 0;
|
||||||
HttpRequestMethod requestMethod;
|
HttpRequestMethod requestMethod;
|
||||||
|
|
||||||
UInt64 firstRead;
|
uint64_t firstRead;
|
||||||
|
|
||||||
fp = DequeueConnection(server);
|
fp = DequeueConnection(server);
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ HttpServerWorkerThread(void *args)
|
||||||
{
|
{
|
||||||
/* Block for 1 millisecond before continuing so we don't
|
/* Block for 1 millisecond before continuing so we don't
|
||||||
* murder the CPU if the queue is empty. */
|
* murder the CPU if the queue is empty. */
|
||||||
UtilSleepMillis(UInt64Create(0, 1));
|
UtilSleepMillis(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,21 +483,25 @@ HttpServerWorkerThread(void *args)
|
||||||
* happens, UtilGetLine() sets errno to EAGAIN. If we get
|
* happens, UtilGetLine() sets errno to EAGAIN. If we get
|
||||||
* EAGAIN, then clear the error on the stream and try again
|
* EAGAIN, then clear the error on the stream and try again
|
||||||
* after a few ms. This is typically more than enough time for
|
* after a few ms. This is typically more than enough time for
|
||||||
* the client to send data. */
|
* the client to send data.
|
||||||
firstRead = UtilServerTs();
|
*
|
||||||
|
* TODO: Instead of looping, abort immediately, and place the request
|
||||||
|
* at the end of the queue.
|
||||||
|
*/
|
||||||
|
firstRead = UtilTsMillis();
|
||||||
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
while ((lineLen = UtilGetLine(&line, &lineSize, fp)) == -1
|
||||||
&& errno == EAGAIN)
|
&& errno == EAGAIN)
|
||||||
{
|
{
|
||||||
StreamClearError(fp);
|
StreamClearError(fp);
|
||||||
|
|
||||||
/* If the server is stopped, or it's been a while, just
|
// If the server is stopped, or it's been a while, just
|
||||||
* give up so we aren't wasting a thread on this client. */
|
// give up so we aren't wasting a thread on this client.
|
||||||
if (server->stop || UInt64Gt(UInt64Sub(UtilServerTs(), firstRead), UInt64Create(0, 1000 * 30)))
|
if (server->stop || (UtilTsMillis() - firstRead) > (1000 * 30))
|
||||||
{
|
{
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
UtilSleepMillis(UInt64Create(0, 5));
|
UtilSleepMillis(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lineLen == -1)
|
if (lineLen == -1)
|
||||||
|
@ -711,25 +715,25 @@ HttpServerEventThread(void *args)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
HttpServerStart(HttpServer * server)
|
HttpServerStart(HttpServer * server)
|
||||||
{
|
{
|
||||||
if (!server)
|
if (!server)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server->isRunning)
|
if (server->isRunning)
|
||||||
{
|
{
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pthread_create(&server->socketThread, NULL, HttpServerEventThread, server) != 0)
|
if (pthread_create(&server->socketThread, NULL, HttpServerEventThread, server) != 0)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
399
src/Int64.c
399
src/Int64.c
|
@ -1,399 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation files
|
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <Int64.h>
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include <Log.h>
|
|
||||||
|
|
||||||
#ifdef INT64_NATIVE
|
|
||||||
#define Int64Sign(x) ((int) (((UInt64) (x)) >> 63))
|
|
||||||
#else
|
|
||||||
#define Int64Sign(x) ((int) ((x).i[1] >> 31))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
size_t
|
|
||||||
Int64Str(Int64 x, int base, char *out, size_t len)
|
|
||||||
{
|
|
||||||
static const char symbols[] = "0123456789ABCDEF";
|
|
||||||
|
|
||||||
size_t i = len - 1;
|
|
||||||
size_t j = 0;
|
|
||||||
|
|
||||||
int neg = Int64Sign(x);
|
|
||||||
|
|
||||||
Int64 base64 = Int64Create(0, base);
|
|
||||||
|
|
||||||
/* We only have symbols up to base 16 */
|
|
||||||
if (base < 2 || base > 16)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This algorithm doesn't work on INT64_MIN.
|
|
||||||
*
|
|
||||||
* But it works on all other integers in the range, so we
|
|
||||||
* just scoot the range in by one for now. It's a hack and
|
|
||||||
* I'm not a huge fan of it, but this function is mostly
|
|
||||||
* used in Json, which shouldn't have a range this large
|
|
||||||
* anyway (Json is limited to -2^53 -> 2^53-1).
|
|
||||||
*
|
|
||||||
* Proper fixes are always welcome.
|
|
||||||
*/
|
|
||||||
if (Int64Eq(x, Int64Create(0x80000000, 0x00000000)))
|
|
||||||
{
|
|
||||||
x = Int64Add(x, Int64Create(0, 1));
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
else if (Int64Eq(x, Int64Create(0x7FFFFFFF, 0xFFFFFFFF)))
|
|
||||||
{
|
|
||||||
x = Int64Sub(x, Int64Create(0, 1));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (base != 2 && base != 8 && base != 16 && neg)
|
|
||||||
{
|
|
||||||
x = Int64Neg(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Int64 mod = Int64Rem(x, base64);
|
|
||||||
Int32 low = Int64Low(mod);
|
|
||||||
|
|
||||||
out[i] = symbols[low];
|
|
||||||
i--;
|
|
||||||
x = Int64Div(x, base64);
|
|
||||||
} while (Int64Gt(x, Int64Create(0, 0)));
|
|
||||||
|
|
||||||
if (base != 2 && base != 8 && base != 16)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Binary, octal, and hexadecimal are known to
|
|
||||||
* be bit representations. Everything else (notably
|
|
||||||
* decimal) should include the negative sign.
|
|
||||||
*/
|
|
||||||
if (neg)
|
|
||||||
{
|
|
||||||
out[i] = '-';
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (++i < len)
|
|
||||||
{
|
|
||||||
out[j++] = out[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
out[j] = '\0';
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef INT64_NATIVE
|
|
||||||
|
|
||||||
/* No native 64-bit support, add our own */
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Create(UInt32 high, UInt32 low)
|
|
||||||
{
|
|
||||||
Int64 x;
|
|
||||||
|
|
||||||
x.i[0] = low;
|
|
||||||
x.i[1] = high;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Add(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
Int64 z = Int64Create(0, 0);
|
|
||||||
int carry;
|
|
||||||
|
|
||||||
z.i[0] = x.i[0] + y.i[0];
|
|
||||||
carry = z.i[0] < x.i[0];
|
|
||||||
z.i[1] = x.i[1] + y.i[1] + carry;
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Sub(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64Add(x, Int64Neg(y));
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Mul(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
Int64 z = Int64Create(0, 0);
|
|
||||||
|
|
||||||
int xneg = Int64Sign(x);
|
|
||||||
int yneg = Int64Sign(y);
|
|
||||||
|
|
||||||
if (xneg)
|
|
||||||
{
|
|
||||||
x = Int64Neg(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (yneg)
|
|
||||||
{
|
|
||||||
y = Int64Neg(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* while (y > 0) */
|
|
||||||
while (Int64Gt(y, Int64Create(0, 0)))
|
|
||||||
{
|
|
||||||
/* if (y & 1 != 0) */
|
|
||||||
if (Int64Neq(Int64And(y, Int64Create(0, 1)), Int64Create(0, 0)))
|
|
||||||
{
|
|
||||||
z = Int64Add(z, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
x = Int64Sll(x, 1);
|
|
||||||
y = Int64Sra(y, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xneg != yneg)
|
|
||||||
{
|
|
||||||
z = Int64Neg(z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
Int64 q;
|
|
||||||
Int64 r;
|
|
||||||
} Int64Ldiv;
|
|
||||||
|
|
||||||
static Int64Ldiv
|
|
||||||
Int64LongDivision(Int64 n, Int64 d)
|
|
||||||
{
|
|
||||||
Int64Ldiv o;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
int nneg = Int64Sign(n);
|
|
||||||
int dneg = Int64Sign(d);
|
|
||||||
|
|
||||||
o.q = Int64Create(0, 0);
|
|
||||||
o.r = Int64Create(0, 0);
|
|
||||||
|
|
||||||
if (Int64Eq(d, Int64Create(0, 0)))
|
|
||||||
{
|
|
||||||
raise(SIGFPE);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nneg)
|
|
||||||
{
|
|
||||||
n = Int64Neg(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dneg)
|
|
||||||
{
|
|
||||||
d = Int64Neg(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 63; i >= 0; i--)
|
|
||||||
{
|
|
||||||
Int64 bit = Int64And(Int64Sra(n, i), Int64Create(0, 1));
|
|
||||||
|
|
||||||
o.r = Int64Sll(o.r, 1);
|
|
||||||
o.r = Int64Or(o.r, bit);
|
|
||||||
|
|
||||||
if (Int64Geq(o.r, d))
|
|
||||||
{
|
|
||||||
o.r = Int64Sub(o.r, d);
|
|
||||||
o.q = Int64Or(o.q, Int64Sll(Int64Create(0, 1), i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nneg != dneg)
|
|
||||||
{
|
|
||||||
o.r = Int64Neg(o.r);
|
|
||||||
o.q = Int64Neg(o.q);
|
|
||||||
}
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Div(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64LongDivision(x, y).q;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Rem(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64LongDivision(x, y).r;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Sll(Int64 x, int y)
|
|
||||||
{
|
|
||||||
Int64 z;
|
|
||||||
|
|
||||||
if (!y)
|
|
||||||
{
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
z = Int64Create(0, 0);
|
|
||||||
|
|
||||||
if (y < 32)
|
|
||||||
{
|
|
||||||
z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y);
|
|
||||||
z.i[0] = x.i[0] << y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
z.i[1] = x.i[0] << (y - 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Sra(Int64 x, int y)
|
|
||||||
{
|
|
||||||
Int64 z;
|
|
||||||
|
|
||||||
int neg = Int64Sign(x);
|
|
||||||
|
|
||||||
if (!y)
|
|
||||||
{
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
z = Int64Create(0, 0);
|
|
||||||
|
|
||||||
if (y < 32)
|
|
||||||
{
|
|
||||||
z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y);
|
|
||||||
z.i[1] = x.i[1] >> y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
z.i[0] = x.i[1] >> (y - 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (neg)
|
|
||||||
{
|
|
||||||
Int64 mask = Int64Create(0xFFFFFFFF, 0xFFFFFFFF);
|
|
||||||
|
|
||||||
z = Int64Or(Int64Sll(mask, (64 - y)), z);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64And(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Or(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Xor(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return Int64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Int64
|
|
||||||
Int64Not(Int64 x)
|
|
||||||
{
|
|
||||||
return Int64Create(~(x.i[1]), ~(x.i[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Int64Eq(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
return x.i[0] == y.i[0] && x.i[1] == y.i[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Int64Lt(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
int xneg = Int64Sign(x);
|
|
||||||
int yneg = Int64Sign(y);
|
|
||||||
|
|
||||||
if (xneg != yneg)
|
|
||||||
{
|
|
||||||
return xneg > yneg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (xneg)
|
|
||||||
{
|
|
||||||
/* Both negative */
|
|
||||||
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Both positive */
|
|
||||||
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Int64Gt(Int64 x, Int64 y)
|
|
||||||
{
|
|
||||||
int xneg = Int64Sign(x);
|
|
||||||
int yneg = Int64Sign(y);
|
|
||||||
|
|
||||||
if (xneg != yneg)
|
|
||||||
{
|
|
||||||
return xneg < yneg;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (xneg)
|
|
||||||
{
|
|
||||||
/* Both negative */
|
|
||||||
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Both positive */
|
|
||||||
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
59
src/Json.c
59
src/Json.c
|
@ -26,14 +26,15 @@
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Int.h>
|
|
||||||
#include <Int64.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
struct JsonValue
|
struct JsonValue
|
||||||
|
@ -44,9 +45,9 @@ struct JsonValue
|
||||||
HashMap *object;
|
HashMap *object;
|
||||||
Array *array;
|
Array *array;
|
||||||
char *string;
|
char *string;
|
||||||
Int64 integer;
|
uint64_t integer;
|
||||||
double floating;
|
double floating;
|
||||||
int boolean:1;
|
bool boolean;
|
||||||
} as;
|
} as;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,7 +202,7 @@ JsonValueAsString(JsonValue * value)
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonValue *
|
JsonValue *
|
||||||
JsonValueInteger(Int64 integer)
|
JsonValueInteger(uint64_t integer)
|
||||||
{
|
{
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
|
|
||||||
|
@ -217,12 +218,12 @@ JsonValueInteger(Int64 integer)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Int64
|
uint64_t
|
||||||
JsonValueAsInteger(JsonValue * value)
|
JsonValueAsInteger(JsonValue * value)
|
||||||
{
|
{
|
||||||
if (!value || value->type != JSON_INTEGER)
|
if (!value || value->type != JSON_INTEGER)
|
||||||
{
|
{
|
||||||
return Int64Create(0, 0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value->as.integer;
|
return value->as.integer;
|
||||||
|
@ -258,7 +259,7 @@ JsonValueAsFloat(JsonValue * value)
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonValue *
|
JsonValue *
|
||||||
JsonValueBoolean(int boolean)
|
JsonValueBoolean(bool boolean)
|
||||||
{
|
{
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
|
|
||||||
|
@ -274,12 +275,12 @@ JsonValueBoolean(int boolean)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
JsonValueAsBoolean(JsonValue * value)
|
JsonValueAsBoolean(JsonValue * value)
|
||||||
{
|
{
|
||||||
if (!value || value->type != JSON_BOOLEAN)
|
if (!value || value->type != JSON_BOOLEAN)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return value->as.boolean;
|
return value->as.boolean;
|
||||||
|
@ -335,12 +336,12 @@ JsonValueFree(JsonValue * value)
|
||||||
Free(value);
|
Free(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
size_t
|
||||||
JsonEncodeString(const char *str, Stream * out)
|
JsonEncodeString(const char *str, Stream * out)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
char c;
|
char c;
|
||||||
int length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
StreamPutc(out, '"');
|
StreamPutc(out, '"');
|
||||||
length++;
|
length++;
|
||||||
|
@ -403,9 +404,9 @@ JsonDecodeString(Stream * in)
|
||||||
int c;
|
int c;
|
||||||
char a[5];
|
char a[5];
|
||||||
|
|
||||||
UInt32 codepoint;
|
uint32_t codepoint;
|
||||||
UInt16 high;
|
uint16_t high;
|
||||||
UInt16 low;
|
uint16_t low;
|
||||||
|
|
||||||
char *utf8Ptr;
|
char *utf8Ptr;
|
||||||
|
|
||||||
|
@ -422,7 +423,7 @@ JsonDecodeString(Stream * in)
|
||||||
{
|
{
|
||||||
if (c <= 0x001F)
|
if (c <= 0x001F)
|
||||||
{
|
{
|
||||||
/* Bad byte; these must be escaped */
|
/* Bad byte; these must be escaped */
|
||||||
Free(str);
|
Free(str);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -598,15 +599,13 @@ JsonDecodeString(Stream * in)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
size_t
|
||||||
JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t len;
|
size_t len;
|
||||||
Array *arr;
|
Array *arr;
|
||||||
int length = 0;
|
size_t length = 0;
|
||||||
|
|
||||||
char ibuf[INT64_STRBUF];
|
|
||||||
|
|
||||||
switch (value->type)
|
switch (value->type)
|
||||||
{
|
{
|
||||||
|
@ -644,8 +643,7 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
||||||
length += JsonEncodeString(value->as.string, out);
|
length += JsonEncodeString(value->as.string, out);
|
||||||
break;
|
break;
|
||||||
case JSON_INTEGER:
|
case JSON_INTEGER:
|
||||||
Int64Str(value->as.integer, 10, ibuf, INT64_STRBUF);
|
length += StreamPrintf(out, "%" PRId64, value->as.integer);
|
||||||
length += StreamPrintf(out, "%s", ibuf);
|
|
||||||
break;
|
break;
|
||||||
case JSON_FLOAT:
|
case JSON_FLOAT:
|
||||||
length += StreamPrintf(out, "%f", value->as.floating);
|
length += StreamPrintf(out, "%f", value->as.floating);
|
||||||
|
@ -673,14 +671,14 @@ JsonEncodeValue(JsonValue * value, Stream * out, int level)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
size_t
|
||||||
JsonEncode(HashMap * object, Stream * out, int level)
|
JsonEncode(HashMap * object, Stream * out, int level)
|
||||||
{
|
{
|
||||||
size_t index;
|
size_t index;
|
||||||
size_t count;
|
size_t count;
|
||||||
char *key;
|
char *key;
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
int length;
|
size_t length;
|
||||||
|
|
||||||
if (!object)
|
if (!object)
|
||||||
{
|
{
|
||||||
|
@ -863,6 +861,7 @@ JsonConsumeWhitespace(JsonParserState * state)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This logic should be moved into Stream as a sync function.
|
||||||
if (StreamError(state->stream))
|
if (StreamError(state->stream))
|
||||||
{
|
{
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
|
@ -876,7 +875,7 @@ JsonConsumeWhitespace(JsonParserState * state)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UtilSleepMillis(UInt64Create(0, delay));
|
UtilSleepMillis(delay);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1123,7 +1122,7 @@ JsonDecodeValue(JsonParserState * state)
|
||||||
JsonValue *value;
|
JsonValue *value;
|
||||||
char *strValue;
|
char *strValue;
|
||||||
|
|
||||||
Int64 iValue;
|
int64_t iValue;
|
||||||
size_t i;
|
size_t i;
|
||||||
int neg;
|
int neg;
|
||||||
|
|
||||||
|
@ -1146,7 +1145,7 @@ JsonDecodeValue(JsonParserState * state)
|
||||||
Free(strValue);
|
Free(strValue);
|
||||||
break;
|
break;
|
||||||
case TOKEN_INTEGER:
|
case TOKEN_INTEGER:
|
||||||
iValue = Int64Create(0, 0);
|
iValue = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
neg = 0;
|
neg = 0;
|
||||||
|
|
||||||
|
@ -1162,14 +1161,14 @@ JsonDecodeValue(JsonParserState * state)
|
||||||
}
|
}
|
||||||
|
|
||||||
d = state->token[i] - '0';
|
d = state->token[i] - '0';
|
||||||
iValue = Int64Mul(iValue, Int64Create(0, 10));
|
iValue *= 10;
|
||||||
iValue = Int64Add(iValue, Int64Create(0, d));
|
iValue += d;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (neg)
|
if (neg)
|
||||||
{
|
{
|
||||||
iValue = Int64Neg(iValue);
|
iValue *= -1;
|
||||||
}
|
}
|
||||||
value = JsonValueInteger(iValue);
|
value = JsonValueInteger(iValue);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -32,8 +32,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <Int.h>
|
|
||||||
|
|
||||||
#ifndef MEMORY_TABLE_CHUNK
|
#ifndef MEMORY_TABLE_CHUNK
|
||||||
#define MEMORY_TABLE_CHUNK 256
|
#define MEMORY_TABLE_CHUNK 256
|
||||||
#endif
|
#endif
|
||||||
|
@ -50,12 +48,12 @@ struct MemoryInfo
|
||||||
void *pointer;
|
void *pointer;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MEM_BOUND_TYPE UInt32
|
#define MEM_BOUND_TYPE uint32_t
|
||||||
#define MEM_BOUND 0xDEADBEEF
|
#define MEM_BOUND 0xDEADBEEF
|
||||||
|
|
||||||
#define MEM_BOUND_LOWER(p) *((MEM_BOUND_TYPE *) p)
|
#define MEM_BOUND_LOWER(p) *((MEM_BOUND_TYPE *) p)
|
||||||
#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((UInt8 *) p) + x)) + 1)
|
#define MEM_BOUND_UPPER(p, x) *(((MEM_BOUND_TYPE *) (((uint8_t *) p) + x)) + 1)
|
||||||
#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(UInt8)) + (2 * sizeof(MEM_BOUND_TYPE)))
|
#define MEM_SIZE_ACTUAL(x) (((x) * sizeof(uint8_t)) + (2 * sizeof(MEM_BOUND_TYPE)))
|
||||||
|
|
||||||
static pthread_mutex_t lock;
|
static pthread_mutex_t lock;
|
||||||
static void (*hook) (MemoryAction, MemoryInfo *, void *) = MemoryDefaultHook;
|
static void (*hook) (MemoryAction, MemoryInfo *, void *) = MemoryDefaultHook;
|
||||||
|
|
18
src/Queue.c
18
src/Queue.c
|
@ -75,39 +75,39 @@ QueueFree(Queue * q)
|
||||||
Free(q);
|
Free(q);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
QueueFull(Queue * q)
|
QueueFull(Queue * q)
|
||||||
{
|
{
|
||||||
if (!q)
|
if (!q)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((q->front == q->rear + 1) || (q->front == 0 && q->rear == q->size - 1));
|
return ((q->front == q->rear + 1) || (q->front == 0 && q->rear == q->size - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
QueueEmpty(Queue * q)
|
QueueEmpty(Queue * q)
|
||||||
{
|
{
|
||||||
if (!q)
|
if (!q)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return q->front == q->size + 1;
|
return (q->front == (q->size + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
QueuePush(Queue * q, void *element)
|
QueuePush(Queue * q, void *element)
|
||||||
{
|
{
|
||||||
if (!q || !element)
|
if (!q || !element)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QueueFull(q))
|
if (QueueFull(q))
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (q->front == q->size + 1)
|
if (q->front == q->size + 1)
|
||||||
|
@ -126,7 +126,7 @@ QueuePush(Queue * q, void *element)
|
||||||
|
|
||||||
q->items[q->rear] = element;
|
q->items[q->rear] = element;
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
|
34
src/Rand.c
34
src/Rand.c
|
@ -23,12 +23,12 @@
|
||||||
*/
|
*/
|
||||||
#include <Rand.h>
|
#include <Rand.h>
|
||||||
|
|
||||||
#include <Int.h>
|
|
||||||
#include <UInt64.h>
|
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
|
|
||||||
typedef struct RandState
|
typedef struct RandState
|
||||||
{
|
{
|
||||||
UInt32 mt[RAND_STATE_VECTOR_LENGTH];
|
uint32_t mt[RAND_STATE_VECTOR_LENGTH];
|
||||||
int index;
|
int index;
|
||||||
} RandState;
|
} RandState;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
RandSeed(RandState * state, UInt32 seed)
|
RandSeed(RandState * state, uint32_t seed)
|
||||||
{
|
{
|
||||||
state->mt[0] = seed & 0xFFFFFFFF;
|
state->mt[0] = seed & 0xFFFFFFFF;
|
||||||
|
|
||||||
|
@ -57,12 +57,12 @@ RandSeed(RandState * state, UInt32 seed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static UInt32
|
static uint32_t
|
||||||
RandGenerate(RandState * state)
|
RandGenerate(RandState * state)
|
||||||
{
|
{
|
||||||
static const UInt32 mag[2] = {0x0, 0x9908B0DF};
|
static const uint32_t mag[2] = {0x0, 0x9908B0DF};
|
||||||
|
|
||||||
UInt32 result;
|
uint32_t result;
|
||||||
|
|
||||||
if (state->index >= RAND_STATE_VECTOR_LENGTH || state->index < 0)
|
if (state->index >= RAND_STATE_VECTOR_LENGTH || state->index < 0)
|
||||||
{
|
{
|
||||||
|
@ -118,22 +118,22 @@ RandDestructor(void *p)
|
||||||
/* This algorithm therefore computes N random numbers generally in O(N)
|
/* This algorithm therefore computes N random numbers generally in O(N)
|
||||||
* time, while being less biased. */
|
* time, while being less biased. */
|
||||||
void
|
void
|
||||||
RandIntN(int *buf, size_t size, unsigned int max)
|
RandIntN(uint32_t *buf, size_t size, uint32_t max)
|
||||||
{
|
{
|
||||||
static pthread_key_t stateKey;
|
static pthread_key_t stateKey;
|
||||||
static int createdKey = 0;
|
static bool createdKey = false;
|
||||||
|
|
||||||
/* Limit the range to banish all previously biased results */
|
/* Limit the range to banish all previously biased results */
|
||||||
const int allowed = RAND_MAX - RAND_MAX % max;
|
const uint32_t allowed = RAND_MAX - RAND_MAX % max;
|
||||||
|
|
||||||
RandState *state;
|
RandState *state;
|
||||||
int tmp;
|
uint32_t tmp;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!createdKey)
|
if (!createdKey)
|
||||||
{
|
{
|
||||||
pthread_key_create(&stateKey, RandDestructor);
|
pthread_key_create(&stateKey, RandDestructor);
|
||||||
createdKey = 1;
|
createdKey = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
state = pthread_getspecific(stateKey);
|
state = pthread_getspecific(stateKey);
|
||||||
|
@ -141,8 +141,8 @@ RandIntN(int *buf, size_t size, unsigned int max)
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
/* Generate a seed from the system time, PID, and TID */
|
/* Generate a seed from the system time, PID, and TID */
|
||||||
UInt64 ts = UtilServerTs();
|
uint64_t ts = UtilTsMillis();
|
||||||
UInt32 seed = UInt64Low(ts) ^ getpid() ^ (unsigned long) pthread_self();
|
uint32_t seed = ts ^ getpid() ^ (unsigned long) pthread_self();
|
||||||
|
|
||||||
state = Malloc(sizeof(RandState));
|
state = Malloc(sizeof(RandState));
|
||||||
RandSeed(state, seed);
|
RandSeed(state, seed);
|
||||||
|
@ -164,10 +164,10 @@ RandIntN(int *buf, size_t size, unsigned int max)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate just 1 random number */
|
/* Generate just 1 random number */
|
||||||
int
|
uint32_t
|
||||||
RandInt(unsigned int max)
|
RandInt(uint32_t max)
|
||||||
{
|
{
|
||||||
int val = 0;
|
uint32_t val = 0;
|
||||||
|
|
||||||
RandIntN(&val, 1, max);
|
RandIntN(&val, 1, max);
|
||||||
return val;
|
return val;
|
||||||
|
|
|
@ -38,11 +38,11 @@ HexDump(size_t off, char *hexBuf, char *asciiBuf, void *args)
|
||||||
|
|
||||||
if (hexBuf && asciiBuf)
|
if (hexBuf && asciiBuf)
|
||||||
{
|
{
|
||||||
fprintf(report, "%04lx: %s | %s |\n", off, hexBuf, asciiBuf);
|
fprintf(report, "%04zx: %s | %s |\n", off, hexBuf, asciiBuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(report, "%04lx\n", off);
|
fprintf(report, "%04zx\n", off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ MemoryIterator(MemoryInfo * i, void *args)
|
||||||
{
|
{
|
||||||
FILE *report = args;
|
FILE *report = args;
|
||||||
|
|
||||||
fprintf(report, "%s:%d: %lu bytes at %p\n",
|
fprintf(report, "%s:%d: %zu bytes at %p\n",
|
||||||
MemoryInfoGetFile(i), MemoryInfoGetLine(i),
|
MemoryInfoGetFile(i), MemoryInfoGetLine(i),
|
||||||
MemoryInfoGetSize(i), MemoryInfoGetPointer(i));
|
MemoryInfoGetSize(i), MemoryInfoGetPointer(i));
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ GenerateMemoryReport(int argc, char **argv)
|
||||||
fprintf(report, " '%s'", argv[i]);
|
fprintf(report, " '%s'", argv[i]);
|
||||||
}
|
}
|
||||||
fprintf(report, "\nDate: %s\n", tsBuffer);
|
fprintf(report, "\nDate: %s\n", tsBuffer);
|
||||||
fprintf(report, "Total Bytes: %lu\n", MemoryAllocated());
|
fprintf(report, "Total Bytes: %zu\n", MemoryAllocated());
|
||||||
fprintf(report, "\n");
|
fprintf(report, "\n");
|
||||||
|
|
||||||
MemoryIterate(MemoryIterator, report);
|
MemoryIterate(MemoryIterator, report);
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
#include <Sha.h>
|
#include <Sha.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Int.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -31,10 +30,10 @@
|
||||||
|
|
||||||
#define LOAD32H(x, y) \
|
#define LOAD32H(x, y) \
|
||||||
{ \
|
{ \
|
||||||
x = ((UInt32)((y)[0] & 255) << 24) | \
|
x = ((uint32_t)((y)[0] & 255) << 24) | \
|
||||||
((UInt32)((y)[1] & 255) << 16) | \
|
((uint32_t)((y)[1] & 255) << 16) | \
|
||||||
((UInt32)((y)[2] & 255) << 8) | \
|
((uint32_t)((y)[2] & 255) << 8) | \
|
||||||
((UInt32)((y)[3] & 255)); \
|
((uint32_t)((y)[3] & 255)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROL(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
#define ROL(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||||
|
@ -49,22 +48,22 @@
|
||||||
|
|
||||||
typedef union
|
typedef union
|
||||||
{
|
{
|
||||||
UInt8 c[64];
|
uint8_t c[64];
|
||||||
UInt32 l[16];
|
uint32_t l[16];
|
||||||
} Char64Long16;
|
} Char64Long16;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
UInt32 state[5];
|
uint32_t state[5];
|
||||||
UInt32 count[2];
|
uint32_t count[2];
|
||||||
UInt8 buffer[64];
|
uint8_t buffer[64];
|
||||||
} Sha1Context;
|
} Sha1Context;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Sha1Transform(UInt32 state[5], const UInt8 buffer[64])
|
Sha1Transform(uint32_t state[5], const uint8_t *buffer)
|
||||||
{
|
{
|
||||||
UInt32 a, b, c, d, e, i;
|
uint32_t a, b, c, d, e, i;
|
||||||
UInt8 workspace[64];
|
uint8_t workspace[64];
|
||||||
Char64Long16 *block = (Char64Long16 *) workspace;
|
Char64Long16 *block = (Char64Long16 *) workspace;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
for (i = 0; i < 16; i++)
|
||||||
|
@ -180,9 +179,9 @@ Sha1Init(Sha1Context * ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size)
|
Sha1Update(Sha1Context * ctx, const void *buf, uint32_t size)
|
||||||
{
|
{
|
||||||
UInt32 i, j;
|
uint32_t i, j;
|
||||||
|
|
||||||
j = (ctx->count[0] >> 3) & 63;
|
j = (ctx->count[0] >> 3) & 63;
|
||||||
|
|
||||||
|
@ -202,7 +201,7 @@ Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size)
|
||||||
|
|
||||||
for (; i + 63 < size; i += 64)
|
for (; i + 63 < size; i += 64)
|
||||||
{
|
{
|
||||||
Sha1Transform(ctx->state, (UInt8 *) buf + i);
|
Sha1Transform(ctx->state, (uint8_t *) buf + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
|
@ -212,14 +211,14 @@ Sha1Update(Sha1Context * ctx, const void *buf, UInt32 size)
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&ctx->buffer[j], &((UInt8 *) buf)[i], size - i);
|
memcpy(&ctx->buffer[j], &((uint8_t *) buf)[i], size - i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Sha1Calculate(Sha1Context * ctx, unsigned char *out)
|
Sha1Calculate(Sha1Context * ctx, unsigned char *out)
|
||||||
{
|
{
|
||||||
UInt32 i;
|
uint32_t i;
|
||||||
UInt8 count[8];
|
uint8_t count[8];
|
||||||
|
|
||||||
for (i = 0; i < 8; i++)
|
for (i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
|
@ -227,16 +226,16 @@ Sha1Calculate(Sha1Context * ctx, unsigned char *out)
|
||||||
>> ((3 - (i & 3)) * 8)) & 255);
|
>> ((3 - (i & 3)) * 8)) & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sha1Update(ctx, (UInt8 *) "\x80", 1);
|
Sha1Update(ctx, (uint8_t *) "\x80", 1);
|
||||||
while ((ctx->count[0] & 504) != 448)
|
while ((ctx->count[0] & 504) != 448)
|
||||||
{
|
{
|
||||||
Sha1Update(ctx, (UInt8 *) "\0", 1);
|
Sha1Update(ctx, (uint8_t *) "\0", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sha1Update(ctx, count, 8);
|
Sha1Update(ctx, count, 8);
|
||||||
for (i = 0; i < (160 / 8); i++)
|
for (i = 0; i < (160 / 8); i++)
|
||||||
{
|
{
|
||||||
out[i] = (UInt8) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
out[i] = (uint8_t) ((ctx->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
*/
|
*/
|
||||||
#include <Sha.h>
|
#include <Sha.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Int.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -31,10 +30,10 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
#define GET_UINT32(x) \
|
#define GET_UINT32(x) \
|
||||||
(((UInt32)(x)[0] << 24) | \
|
(((uint32_t)(x)[0] << 24) | \
|
||||||
((UInt32)(x)[1] << 16) | \
|
((uint32_t)(x)[1] << 16) | \
|
||||||
((UInt32)(x)[2] << 8) | \
|
((uint32_t)(x)[2] << 8) | \
|
||||||
((UInt32)(x)[3]))
|
((uint32_t)(x)[3]))
|
||||||
|
|
||||||
#define PUT_UINT32(dst, x) { \
|
#define PUT_UINT32(dst, x) { \
|
||||||
(dst)[0] = (x) >> 24; \
|
(dst)[0] = (x) >> 24; \
|
||||||
|
@ -56,8 +55,8 @@
|
||||||
#define WW(i) (w[i] = w[i - 16] + S0(w[i - 15]) + w[i - 7] + S1(w[i - 2]))
|
#define WW(i) (w[i] = w[i - 16] + S0(w[i - 15]) + w[i - 7] + S1(w[i - 2]))
|
||||||
|
|
||||||
#define ROUND(a, b, c, d, e, f, g, h, k, w) { \
|
#define ROUND(a, b, c, d, e, f, g, h, k, w) { \
|
||||||
UInt32 tmp0 = h + T0(e) + CH(e, f, g) + k + w; \
|
uint32_t tmp0 = h + T0(e) + CH(e, f, g) + k + w; \
|
||||||
UInt32 tmp1 = T1(a) + MAJ(a, b, c); \
|
uint32_t tmp1 = T1(a) + MAJ(a, b, c); \
|
||||||
h = tmp0 + tmp1; \
|
h = tmp0 + tmp1; \
|
||||||
d += tmp0; \
|
d += tmp0; \
|
||||||
}
|
}
|
||||||
|
@ -65,7 +64,7 @@
|
||||||
typedef struct Sha256Context
|
typedef struct Sha256Context
|
||||||
{
|
{
|
||||||
size_t length;
|
size_t length;
|
||||||
UInt32 state[8];
|
uint32_t state[8];
|
||||||
size_t bufLen;
|
size_t bufLen;
|
||||||
unsigned char buffer[64];
|
unsigned char buffer[64];
|
||||||
} Sha256Context;
|
} Sha256Context;
|
||||||
|
@ -73,7 +72,7 @@ typedef struct Sha256Context
|
||||||
static void
|
static void
|
||||||
Sha256Chunk(Sha256Context * context, unsigned char chunk[64])
|
Sha256Chunk(Sha256Context * context, unsigned char chunk[64])
|
||||||
{
|
{
|
||||||
const UInt32 rk[64] = {
|
const uint32_t rk[64] = {
|
||||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
|
||||||
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
|
||||||
|
@ -87,8 +86,8 @@ Sha256Chunk(Sha256Context * context, unsigned char chunk[64])
|
||||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt32 w[64];
|
uint32_t w[64];
|
||||||
UInt32 a, b, c, d, e, f, g, h;
|
uint32_t a, b, c, d, e, f, g, h;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -178,10 +177,10 @@ Sha256(char *str)
|
||||||
unsigned char *out;
|
unsigned char *out;
|
||||||
|
|
||||||
unsigned char fill[64];
|
unsigned char fill[64];
|
||||||
UInt32 fillLen;
|
uint32_t fillLen;
|
||||||
unsigned char buf[8];
|
unsigned char buf[8];
|
||||||
UInt32 hiLen;
|
uint32_t hiLen;
|
||||||
UInt32 loLen;
|
uint32_t loLen;
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
{
|
{
|
||||||
|
@ -213,8 +212,8 @@ Sha256(char *str)
|
||||||
fill[0] = 0x80;
|
fill[0] = 0x80;
|
||||||
|
|
||||||
fillLen = (context.bufLen < 56) ? 56 - context.bufLen : 120 - context.bufLen;
|
fillLen = (context.bufLen < 56) ? 56 - context.bufLen : 120 - context.bufLen;
|
||||||
hiLen = (UInt32) (context.length >> 29);
|
hiLen = (uint32_t) (context.length >> 29);
|
||||||
loLen = (UInt32) (context.length << 3);
|
loLen = (uint32_t) (context.length << 3);
|
||||||
|
|
||||||
PUT_UINT32(&buf[0], hiLen);
|
PUT_UINT32(&buf[0], hiLen);
|
||||||
PUT_UINT32(&buf[4], loLen);
|
PUT_UINT32(&buf[4], loLen);
|
||||||
|
|
23
src/Str.c
23
src/Str.c
|
@ -26,7 +26,6 @@
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Rand.h>
|
#include <Rand.h>
|
||||||
#include <Int.h>
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -35,8 +34,8 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
UInt32
|
uint32_t
|
||||||
StrUtf16Decode(UInt16 high, UInt16 low)
|
StrUtf16Decode(uint16_t high, uint16_t low)
|
||||||
{
|
{
|
||||||
if (high <= 0xD7FF)
|
if (high <= 0xD7FF)
|
||||||
{
|
{
|
||||||
|
@ -56,7 +55,7 @@ StrUtf16Decode(UInt16 high, UInt16 low)
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
StrUtf8Encode(UInt32 codepoint)
|
StrUtf8Encode(uint32_t codepoint)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
|
@ -220,10 +219,10 @@ StrConcat(size_t nStr,...)
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
StrBlank(const char *str)
|
StrBlank(const char *str)
|
||||||
{
|
{
|
||||||
int blank = 1;
|
bool blank = true;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
while (str[i])
|
while (str[i])
|
||||||
|
@ -245,7 +244,7 @@ StrRandom(size_t len)
|
||||||
static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
static const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
char *str;
|
char *str;
|
||||||
int *nums;
|
uint32_t *nums;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
|
@ -260,7 +259,7 @@ StrRandom(size_t len)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
nums = Malloc(len * sizeof(int));
|
nums = Malloc(len * sizeof(uint32_t));
|
||||||
if (!nums)
|
if (!nums)
|
||||||
{
|
{
|
||||||
Free(str);
|
Free(str);
|
||||||
|
@ -323,21 +322,21 @@ StrLower(char *str)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
StrEquals(const char *str1, const char *str2)
|
StrEquals(const char *str1, const char *str2)
|
||||||
{
|
{
|
||||||
/* Both strings are NULL, they're equal */
|
/* Both strings are NULL, they're equal */
|
||||||
if (!str1 && !str2)
|
if (!str1 && !str2)
|
||||||
{
|
{
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* One or the other is NULL, they're not equal */
|
/* One or the other is NULL, they're not equal */
|
||||||
if (!str1 || !str2)
|
if (!str1 || !str2)
|
||||||
{
|
{
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Neither are NULL, do a regular string comparison */
|
/* Neither are NULL, do a regular string comparison */
|
||||||
return strcmp(str1, str2) == 0;
|
return (strcmp(str1, str2) == 0);
|
||||||
}
|
}
|
||||||
|
|
11
src/Stream.c
11
src/Stream.c
|
@ -26,7 +26,6 @@
|
||||||
#include <Io.h>
|
#include <Io.h>
|
||||||
#include <Memory.h>
|
#include <Memory.h>
|
||||||
#include <Util.h>
|
#include <Util.h>
|
||||||
#include <Int.h>
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -50,11 +49,11 @@ struct Stream
|
||||||
{
|
{
|
||||||
Io *io;
|
Io *io;
|
||||||
|
|
||||||
UInt8 *rBuf;
|
uint8_t *rBuf;
|
||||||
size_t rLen;
|
size_t rLen;
|
||||||
size_t rOff;
|
size_t rOff;
|
||||||
|
|
||||||
UInt8 *wBuf;
|
uint8_t *wBuf;
|
||||||
size_t wLen;
|
size_t wLen;
|
||||||
|
|
||||||
char *ugBuf;
|
char *ugBuf;
|
||||||
|
@ -550,13 +549,13 @@ StreamSeek(Stream * stream, off_t offset, int whence)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
StreamEof(Stream * stream)
|
StreamEof(Stream * stream)
|
||||||
{
|
{
|
||||||
return stream && (stream->flags & STREAM_EOF);
|
return stream && (stream->flags & STREAM_EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
bool
|
||||||
StreamError(Stream * stream)
|
StreamError(Stream * stream)
|
||||||
{
|
{
|
||||||
return stream && (stream->flags & STREAM_ERR);
|
return stream && (stream->flags & STREAM_ERR);
|
||||||
|
@ -626,7 +625,7 @@ StreamCopy(Stream * in, Stream * out)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UtilSleepMillis(UInt64Create(0, STREAM_DELAY));
|
UtilSleepMillis(STREAM_DELAY);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
265
src/UInt64.c
265
src/UInt64.c
|
@ -1,265 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation files
|
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
#include <UInt64.h>
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
size_t
|
|
||||||
UInt64Str(UInt64 x, int base, char *out, size_t len)
|
|
||||||
{
|
|
||||||
static const char symbols[] = "0123456789ABCDEF";
|
|
||||||
|
|
||||||
size_t i = len - 1;
|
|
||||||
size_t j = 0;
|
|
||||||
|
|
||||||
UInt64 base64 = UInt64Create(0, base);
|
|
||||||
|
|
||||||
/* We only have symbols up to base 16 */
|
|
||||||
if (base < 2 || base > 16)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
UInt64 mod = UInt64Rem(x, base64);
|
|
||||||
UInt32 low = UInt64Low(mod);
|
|
||||||
|
|
||||||
out[i] = symbols[low];
|
|
||||||
i--;
|
|
||||||
x = UInt64Div(x, base64);
|
|
||||||
} while (UInt64Gt(x, UInt64Create(0, 0)));
|
|
||||||
|
|
||||||
while (++i < len)
|
|
||||||
{
|
|
||||||
out[j++] = out[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
out[j] = '\0';
|
|
||||||
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef UINT64_NATIVE
|
|
||||||
|
|
||||||
/* No native 64-bit support, add our own */
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Create(UInt32 high, UInt32 low)
|
|
||||||
{
|
|
||||||
UInt64 x;
|
|
||||||
|
|
||||||
x.i[0] = low;
|
|
||||||
x.i[1] = high;
|
|
||||||
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Add(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
UInt64 z = UInt64Create(0, 0);
|
|
||||||
int carry;
|
|
||||||
|
|
||||||
z.i[0] = x.i[0] + y.i[0];
|
|
||||||
carry = z.i[0] < x.i[0];
|
|
||||||
z.i[1] = x.i[1] + y.i[1] + carry;
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Sub(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
UInt64 twosCompl = UInt64Add(UInt64Not(y), UInt64Create(0, 1));
|
|
||||||
|
|
||||||
return UInt64Add(x, twosCompl);
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Mul(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
UInt64 z = UInt64Create(0, 0);
|
|
||||||
|
|
||||||
/* while (y > 0) */
|
|
||||||
while (UInt64Gt(y, UInt64Create(0, 0)))
|
|
||||||
{
|
|
||||||
/* if (y & 1 != 0) */
|
|
||||||
if (UInt64Neq(UInt64And(y, UInt64Create(0, 1)), UInt64Create(0, 0)))
|
|
||||||
{
|
|
||||||
z = UInt64Add(z, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
x = UInt64Sll(x, 1);
|
|
||||||
y = UInt64Srl(y, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
UInt64 q;
|
|
||||||
UInt64 r;
|
|
||||||
} UInt64Ldiv;
|
|
||||||
|
|
||||||
static UInt64Ldiv
|
|
||||||
UInt64LongDivision(UInt64 n, UInt64 d)
|
|
||||||
{
|
|
||||||
UInt64Ldiv o;
|
|
||||||
|
|
||||||
int i;
|
|
||||||
|
|
||||||
o.q = UInt64Create(0, 0);
|
|
||||||
o.r = UInt64Create(0, 0);
|
|
||||||
|
|
||||||
if (UInt64Eq(d, UInt64Create(0, 0)))
|
|
||||||
{
|
|
||||||
raise(SIGFPE);
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 63; i >= 0; i--)
|
|
||||||
{
|
|
||||||
UInt64 bit = UInt64And(UInt64Srl(n, i), UInt64Create(0, 1));
|
|
||||||
|
|
||||||
o.r = UInt64Sll(o.r, 1);
|
|
||||||
o.r = UInt64Or(o.r, bit);
|
|
||||||
|
|
||||||
if (UInt64Geq(o.r, d))
|
|
||||||
{
|
|
||||||
o.r = UInt64Sub(o.r, d);
|
|
||||||
o.q = UInt64Or(o.q, UInt64Sll(UInt64Create(0, 1), i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Div(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return UInt64LongDivision(x, y).q;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Rem(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return UInt64LongDivision(x, y).r;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Sll(UInt64 x, int y)
|
|
||||||
{
|
|
||||||
UInt64 z;
|
|
||||||
|
|
||||||
if (!y)
|
|
||||||
{
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
z = UInt64Create(0, 0);
|
|
||||||
|
|
||||||
if (y < 32)
|
|
||||||
{
|
|
||||||
z.i[1] = (x.i[0] >> (32 - y)) | (x.i[1] << y);
|
|
||||||
z.i[0] = x.i[0] << y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
z.i[1] = x.i[0] << (y - 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Srl(UInt64 x, int y)
|
|
||||||
{
|
|
||||||
UInt64 z;
|
|
||||||
|
|
||||||
if (!y)
|
|
||||||
{
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
z = UInt64Create(0, 0);
|
|
||||||
|
|
||||||
if (y < 32)
|
|
||||||
{
|
|
||||||
z.i[0] = (x.i[1] << (32 - y)) | (x.i[0] >> y);
|
|
||||||
z.i[1] = x.i[1] >> y;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
z.i[0] = x.i[1] >> (y - 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64And(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return UInt64Create(x.i[1] & y.i[1], x.i[0] & y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Or(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return UInt64Create(x.i[1] | y.i[1], x.i[0] | y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Xor(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return UInt64Create(x.i[1] ^ y.i[1], x.i[0] ^ y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt64
|
|
||||||
UInt64Not(UInt64 x)
|
|
||||||
{
|
|
||||||
return UInt64Create(~(x.i[1]), ~(x.i[0]));
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
UInt64Eq(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return x.i[0] == y.i[0] && x.i[1] == y.i[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
UInt64Lt(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return x.i[1] < y.i[1] || (x.i[1] == y.i[1] && x.i[0] < y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
UInt64Gt(UInt64 x, UInt64 y)
|
|
||||||
{
|
|
||||||
return x.i[1] > y.i[1] || (x.i[1] == y.i[1] && x.i[0] > y.i[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
81
src/Util.c
81
src/Util.c
|
@ -40,8 +40,6 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <UInt64.h>
|
|
||||||
|
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX 256
|
#define PATH_MAX 256
|
||||||
#endif
|
#endif
|
||||||
|
@ -50,14 +48,14 @@
|
||||||
#define SSIZE_MAX LONG_MAX
|
#define SSIZE_MAX LONG_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
UInt64
|
uint64_t
|
||||||
UtilServerTs(void)
|
UtilTsMillis(void)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
|
||||||
UInt64 ts;
|
uint64_t ts;
|
||||||
UInt64 sec;
|
uint64_t sec;
|
||||||
UInt64 usec;
|
uint64_t usec;
|
||||||
|
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
@ -77,54 +75,31 @@ UtilServerTs(void)
|
||||||
*
|
*
|
||||||
* The same goes for suseconds_t.
|
* The same goes for suseconds_t.
|
||||||
*/
|
*/
|
||||||
if (sizeof(time_t) == sizeof(UInt64))
|
|
||||||
{
|
|
||||||
/* 64 bit time_t: convert it to a 64 bit integer */
|
|
||||||
time_t ms = tv.tv_sec * 1000;
|
|
||||||
UInt32 high = (UInt32) (ms >> 32);
|
|
||||||
UInt32 low = (UInt32) ms;
|
|
||||||
|
|
||||||
sec = UInt64Create(high, low);
|
// Two separate steps because time_t might be 32-bit. In that
|
||||||
}
|
// case, we want the multiplication to happen after the promotion
|
||||||
else
|
// to uint64_t.
|
||||||
{
|
sec = tv.tv_sec;
|
||||||
/* Assume 32 bit time_t: promote to 64 bit, then multiply, in
|
sec *= 1000;
|
||||||
* case multiplication overflows 32 bits. */
|
|
||||||
sec = UInt64Create(0, tv.tv_sec);
|
|
||||||
sec = UInt64Mul(sec, UInt64Create(0, 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
usec = UInt64Create(0, tv.tv_usec / 1000);
|
usec = tv.tv_usec / 1000;
|
||||||
ts = UInt64Add(sec, usec);
|
|
||||||
|
ts = sec + usec;
|
||||||
|
|
||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt64
|
uint64_t
|
||||||
UtilLastModified(char *path)
|
UtilLastModified(char *path)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
UInt64 ts = UInt64Create(0, 0);
|
uint64_t ts = 0;
|
||||||
|
|
||||||
if (stat(path, &st) == 0)
|
if (stat(path, &st) == 0)
|
||||||
{
|
{
|
||||||
if (sizeof(time_t) == sizeof(UInt64))
|
ts = st.st_mtim.tv_sec;
|
||||||
{
|
ts *= 1000;
|
||||||
/* 64 bit time_t: convert it to a 64 bit integer */
|
ts += st.st_mtim.tv_nsec / 1000000;
|
||||||
time_t ms = st.st_mtim.tv_sec * 1000;
|
|
||||||
UInt32 high = (UInt32) (ms >> 32);
|
|
||||||
UInt32 low = (UInt32) ms;
|
|
||||||
|
|
||||||
ts = UInt64Create(high, low);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ts = UInt64Create(0, st.st_mtim.tv_sec);
|
|
||||||
ts = UInt64Mul(ts, UInt64Create(0, 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* nsec gauanteed to fit in 32 bits */
|
|
||||||
ts = UInt64Add(ts, UInt64Create(0, st.st_mtim.tv_nsec / 1000000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ts;
|
return ts;
|
||||||
|
@ -202,21 +177,13 @@ UtilMkdir(const char *dir, const mode_t mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
UtilSleepMillis(UInt64 ms)
|
UtilSleepMillis(uint64_t ms)
|
||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (sizeof(time_t) == sizeof(UInt64))
|
ts.tv_sec = ms / 1000;
|
||||||
{
|
ts.tv_nsec = (ms % 1000) * 1000000;
|
||||||
ts.tv_sec = ((time_t) UInt64High(ms) << 32 | UInt64Low(ms)) / 1000;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ts.tv_sec = UInt64Low(ms) / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
ts.tv_nsec = UInt64Low(UInt64Rem(ms, UInt64Create(0, 1000))) * 1000000;
|
|
||||||
|
|
||||||
res = nanosleep(&ts, &ts);
|
res = nanosleep(&ts, &ts);
|
||||||
|
|
||||||
|
@ -312,14 +279,14 @@ ThreadNoDestructor(void *p)
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32
|
uint32_t
|
||||||
UtilThreadNo(void)
|
UtilThreadNo(void)
|
||||||
{
|
{
|
||||||
static pthread_key_t key;
|
static pthread_key_t key;
|
||||||
static int createdKey = 0;
|
static int createdKey = 0;
|
||||||
static unsigned long count = 0;
|
static unsigned long count = 0;
|
||||||
|
|
||||||
UInt32 *no;
|
uint32_t *no;
|
||||||
|
|
||||||
if (!createdKey)
|
if (!createdKey)
|
||||||
{
|
{
|
||||||
|
@ -330,7 +297,7 @@ UtilThreadNo(void)
|
||||||
no = pthread_getspecific(key);
|
no = pthread_getspecific(key);
|
||||||
if (!no)
|
if (!no)
|
||||||
{
|
{
|
||||||
no = malloc(sizeof(UInt32));
|
no = malloc(sizeof(uint32_t));
|
||||||
*no = count++;
|
*no = count++;
|
||||||
pthread_setspecific(key, no);
|
pthread_setspecific(key, no);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The functions in this API operate on an array structure which is
|
* The functions in this API operate on an array structure which is
|
||||||
|
@ -98,7 +99,7 @@ extern void *ArrayGet(Array *, size_t);
|
||||||
* This function returns a boolean value indicating whether or not it
|
* This function returns a boolean value indicating whether or not it
|
||||||
* suceeded.
|
* suceeded.
|
||||||
*/
|
*/
|
||||||
extern int ArrayInsert(Array *, size_t, void *);
|
extern bool ArrayInsert(Array *, size_t, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value at the specified index in the specified array to the
|
* Set the value at the specified index in the specified array to the
|
||||||
|
@ -115,7 +116,7 @@ extern void *ArraySet(Array *, size_t, void *);
|
||||||
* return value as
|
* return value as
|
||||||
* .Fn ArrayInsert .
|
* .Fn ArrayInsert .
|
||||||
*/
|
*/
|
||||||
extern int ArrayAdd(Array *, void *);
|
extern bool ArrayAdd(Array *, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove the element at the specified index from the specified array.
|
* Remove the element at the specified index from the specified array.
|
||||||
|
@ -146,7 +147,7 @@ extern void ArraySort(Array *, int (*) (void *, void *));
|
||||||
* .P
|
* .P
|
||||||
* This is a relatively expensive operation. The array must first be
|
* This is a relatively expensive operation. The array must first be
|
||||||
* duplicated. Then it is sorted, then it is iterated from beginning
|
* duplicated. Then it is sorted, then it is iterated from beginning
|
||||||
* to end to remove duplicate entires. Note that the comparison
|
* to end to remove duplicate entries. Note that the comparison
|
||||||
* function is executed on each element at least twice.
|
* function is executed on each element at least twice.
|
||||||
*/
|
*/
|
||||||
extern Array *ArrayUnique(Array *, int (*) (void *, void *));
|
extern Array *ArrayUnique(Array *, int (*) (void *, void *));
|
||||||
|
@ -167,7 +168,7 @@ extern Array *ArrayReverse(Array *);
|
||||||
* array. This function is intended to be used by functions that return
|
* array. This function is intended to be used by functions that return
|
||||||
* relatively read-only arrays that will be long-lived.
|
* relatively read-only arrays that will be long-lived.
|
||||||
*/
|
*/
|
||||||
extern int ArrayTrim(Array *);
|
extern bool ArrayTrim(Array *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a variadic arguments list into an Array. In most cases, the
|
* Convert a variadic arguments list into an Array. In most cases, the
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function computes the amount of bytes needed to store a message
|
* This function computes the amount of bytes needed to store a message
|
||||||
|
@ -93,7 +94,7 @@ extern void
|
||||||
* this means it will only fail if a bigger string is necessary, but it
|
* this means it will only fail if a bigger string is necessary, but it
|
||||||
* could not be automatically allocated on the heap.
|
* could not be automatically allocated on the heap.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern bool
|
||||||
Base64Pad(char **, size_t);
|
Base64Pad(char **, size_t);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_BASE64_H */
|
#endif /* CYTOPLASM_BASE64_H */
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#ifndef CYTOPLASM_CRON_H
|
#ifndef CYTOPLASM_CRON_H
|
||||||
#define CYTOPLASM_CRON_H
|
#define CYTOPLASM_CRON_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @Nm Cron
|
* @Nm Cron
|
||||||
* @Nd Basic periodic job scheduler.
|
* @Nd Basic periodic job scheduler.
|
||||||
|
@ -56,8 +58,6 @@
|
||||||
* by any means.
|
* by any means.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Int.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All functions defined here operate on a structure opaque to the
|
* All functions defined here operate on a structure opaque to the
|
||||||
* caller.
|
* caller.
|
||||||
|
@ -82,7 +82,7 @@ typedef void (JobFunc) (void *);
|
||||||
* .Pp
|
* .Pp
|
||||||
* This function takes the tick interval in milliseconds.
|
* This function takes the tick interval in milliseconds.
|
||||||
*/
|
*/
|
||||||
extern Cron * CronCreate(UInt32);
|
extern Cron * CronCreate(uint64_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a one-off job to be executed only at the next tick, and
|
* Schedule a one-off job to be executed only at the next tick, and
|
||||||
|
@ -110,7 +110,7 @@ extern void
|
||||||
* and a pointer to pass to that function when it is executed.
|
* and a pointer to pass to that function when it is executed.
|
||||||
*/
|
*/
|
||||||
extern void
|
extern void
|
||||||
CronEvery(Cron *, unsigned long, JobFunc *, void *);
|
CronEvery(Cron *, uint64_t, JobFunc *, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start ticking the clock and executing registered jobs.
|
* Start ticking the clock and executing registered jobs.
|
||||||
|
|
|
@ -24,6 +24,17 @@
|
||||||
#ifndef CYTOPLASM_CYTOPLASM_H
|
#ifndef CYTOPLASM_CYTOPLASM_H
|
||||||
#define CYTOPLASM_CYTOPLASM_H
|
#define CYTOPLASM_CYTOPLASM_H
|
||||||
|
|
||||||
|
#define CYTOPLASM_VERSION_MAJOR 0
|
||||||
|
#define CYTOPLASM_VERSION_MINOR 4
|
||||||
|
#define CYTOPLASM_VERSION_PATCH 1
|
||||||
|
#define CYTOPLASM_VERSION ((CYTOPLASM_VERSION_MAJOR * 10000) + (CYTOPLASM_VERSION_MINOR * 100) + (CYTOPLASM_VERSION_PATCH))
|
||||||
|
|
||||||
|
#define CYTOPLASM_VERSION_ALPHA 1
|
||||||
|
#define CYTOPLASM_VERSION_BETA 0
|
||||||
|
#define CYTOPLASM_VERSION_STABLE (!CYTOPLASM_VERSION_ALPHA && !CYTOPLASM_VERSION_BETA)
|
||||||
|
|
||||||
|
#define STRINGIFY(x) #x
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @Nm Cytoplasm
|
* @Nm Cytoplasm
|
||||||
* @Nd A simple API that provides metadata on the library itself.
|
* @Nd A simple API that provides metadata on the library itself.
|
||||||
|
@ -34,18 +45,8 @@
|
||||||
* currently loaded library.
|
* currently loaded library.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/** */
|
||||||
/**
|
extern int CytoplasmGetVersion(void);
|
||||||
* Get the name that this library was compiled with. In most cases,
|
|
||||||
* this will be hard-coded to "Cytoplasm", but it may differ if, for
|
|
||||||
* some reason, there exists another ABI-compatible library that
|
|
||||||
* wishes to report its name.
|
|
||||||
*
|
|
||||||
* This function really only exists because the information is
|
|
||||||
* available along side of the version information so for
|
|
||||||
* consistency, it made sense to include both.
|
|
||||||
*/
|
|
||||||
extern char * CytoplasmGetName(void);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the library version. This will be useful mostly for printing
|
* Get the library version. This will be useful mostly for printing
|
||||||
|
@ -55,6 +56,6 @@ extern char * CytoplasmGetName(void);
|
||||||
* This function returns a string, which should usually be able to be
|
* This function returns a string, which should usually be able to be
|
||||||
* parsed using sscanf() if absolutely necessary.
|
* parsed using sscanf() if absolutely necessary.
|
||||||
*/
|
*/
|
||||||
extern char * CytoplasmGetVersion(void);
|
extern const char * CytoplasmGetVersionStr(void);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_CYTOPLASM_H */
|
#endif /* CYTOPLASM_CYTOPLASM_H */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "HashMap.h"
|
#include "HashMap.h"
|
||||||
#include "Array.h"
|
#include "Array.h"
|
||||||
|
@ -113,7 +114,7 @@ extern DbRef * DbLock(Db *, size_t,...);
|
||||||
* This function assumes the object is not locked, otherwise undefined
|
* This function assumes the object is not locked, otherwise undefined
|
||||||
* behavior will result.
|
* behavior will result.
|
||||||
*/
|
*/
|
||||||
extern int DbDelete(Db *, size_t,...);
|
extern bool DbDelete(Db *, size_t,...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlock an object and return it back to the database. This function
|
* Unlock an object and return it back to the database. This function
|
||||||
|
@ -121,7 +122,7 @@ extern int DbDelete(Db *, size_t,...);
|
||||||
* read cache; writes are always immediate to ensure data integrity in
|
* read cache; writes are always immediate to ensure data integrity in
|
||||||
* the event of a system failure.
|
* the event of a system failure.
|
||||||
*/
|
*/
|
||||||
extern int DbUnlock(Db *, DbRef *);
|
extern bool DbUnlock(Db *, DbRef *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the existence of the given database object in a more efficient
|
* Check the existence of the given database object in a more efficient
|
||||||
|
@ -130,7 +131,7 @@ extern int DbUnlock(Db *, DbRef *);
|
||||||
* This function does not lock the object, nor does it load it into
|
* This function does not lock the object, nor does it load it into
|
||||||
* memory if it exists.
|
* memory if it exists.
|
||||||
*/
|
*/
|
||||||
extern int DbExists(Db *, size_t,...);
|
extern bool DbExists(Db *, size_t,...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List all of the objects at a given path. Unlike the other varargs
|
* List all of the objects at a given path. Unlike the other varargs
|
||||||
|
@ -164,6 +165,6 @@ extern HashMap * DbJson(DbRef *);
|
||||||
* replace it with new JSON. This is more efficient than duplicating
|
* replace it with new JSON. This is more efficient than duplicating
|
||||||
* a separate object into the database reference.
|
* a separate object into the database reference.
|
||||||
*/
|
*/
|
||||||
extern int DbJsonSet(DbRef *, HashMap *);
|
extern bool DbJsonSet(DbRef *, HashMap *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -150,7 +150,7 @@ extern void * HashMapDelete(HashMap *, const char *);
|
||||||
* insertions or deletions occur during the iteration. This
|
* insertions or deletions occur during the iteration. This
|
||||||
* functionality has not been tested, and will likely not work.
|
* functionality has not been tested, and will likely not work.
|
||||||
*/
|
*/
|
||||||
extern int HashMapIterate(HashMap *, char **, void **);
|
extern bool HashMapIterate(HashMap *, char **, void **);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reentrant version of
|
* A reentrant version of
|
||||||
|
@ -163,7 +163,7 @@ extern int HashMapIterate(HashMap *, char **, void **);
|
||||||
* .Pp
|
* .Pp
|
||||||
* The cursor should be initialized to 0 at the start of iteration.
|
* The cursor should be initialized to 0 at the start of iteration.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern bool
|
||||||
HashMapIterateReentrant(HashMap *, char **, void **, size_t *);
|
HashMapIterateReentrant(HashMap *, char **, void **, size_t *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -74,7 +74,7 @@ extern void HttpRouterFree(HttpRouter *);
|
||||||
* .Pa /some/path/(.*)/parts
|
* .Pa /some/path/(.*)/parts
|
||||||
* to work as one would expect.
|
* to work as one would expect.
|
||||||
*/
|
*/
|
||||||
extern int HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *);
|
extern bool HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route the specified request path using the specified routing
|
* Route the specified request path using the specified routing
|
||||||
|
@ -86,6 +86,6 @@ extern int HttpRouterAdd(HttpRouter *, char *, HttpRouteFunc *);
|
||||||
* how to handle, and the pointer to a void pointer is where the
|
* how to handle, and the pointer to a void pointer is where the
|
||||||
* route function's response will be placed.
|
* route function's response will be placed.
|
||||||
*/
|
*/
|
||||||
extern int HttpRouterRoute(HttpRouter *, char *, void *, void **);
|
extern bool HttpRouterRoute(HttpRouter *, char *, void *, void **);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_HTTPROUTER_H */
|
#endif /* CYTOPLASM_HTTPROUTER_H */
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "Http.h"
|
#include "Http.h"
|
||||||
#include "HashMap.h"
|
#include "HashMap.h"
|
||||||
|
@ -133,7 +134,7 @@ extern void HttpServerFree(HttpServer *);
|
||||||
* caller can continue working while the HTTP server is running in a
|
* caller can continue working while the HTTP server is running in a
|
||||||
* separate thread and managing a pool of threads to handle responses.
|
* separate thread and managing a pool of threads to handle responses.
|
||||||
*/
|
*/
|
||||||
extern int HttpServerStart(HttpServer *);
|
extern bool HttpServerStart(HttpServer *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typically, at some point after calling
|
* Typically, at some point after calling
|
||||||
|
|
|
@ -1,122 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation files
|
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef CYTOPLASM_INT_H
|
|
||||||
#define CYTOPLASM_INT_H
|
|
||||||
|
|
||||||
/***
|
|
||||||
* @Nm Int
|
|
||||||
* @Nd Fixed-width integer types.
|
|
||||||
* @Dd April 27 2023
|
|
||||||
*
|
|
||||||
* This header provides cross-platform, fixed-width integer types.
|
|
||||||
* Specifically, it uses preprocessor magic to define the following
|
|
||||||
* types:
|
|
||||||
* .Bl -bullet -offset indent
|
|
||||||
* .It
|
|
||||||
* Int8 and UInt8
|
|
||||||
* .It
|
|
||||||
* Int16 and UInt16
|
|
||||||
* .It
|
|
||||||
* Int32 and UInt32
|
|
||||||
* .El
|
|
||||||
* .Pp
|
|
||||||
* Note that there is no 64-bit integer type, because the ANSI C
|
|
||||||
* standard makes no guarantee that such a type will exist, even
|
|
||||||
* though it does on most platforms.
|
|
||||||
* .Pp
|
|
||||||
* The reason Cytoplasm provides its own header for this is
|
|
||||||
* because ANSI C does not define fixed-width types, and while it
|
|
||||||
* should be safe to rely on C99 fixed-width types in most cases,
|
|
||||||
* there may be cases where even that is not possible.
|
|
||||||
*
|
|
||||||
* @ignore-typedefs
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#define BIT32_MAX 4294967295UL
|
|
||||||
#define BIT16_MAX 65535UL
|
|
||||||
#define BIT8_MAX 255UL
|
|
||||||
|
|
||||||
#ifndef UCHAR_MAX
|
|
||||||
#error Size of char data type is unknown. Define UCHAR_MAX.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef USHRT_MAX
|
|
||||||
#error Size of short data type is unknown. Define USHRT_MAX.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef UINT_MAX
|
|
||||||
#error Size of int data type is unknown. Define UINT_MAX.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef ULONG_MAX
|
|
||||||
#error Size of long data type is unknown. Define ULONG_MAX.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if UCHAR_MAX == BIT8_MAX
|
|
||||||
typedef signed char Int8;
|
|
||||||
typedef unsigned char UInt8;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error Unable to determine suitable data type for 8-bit integers.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if UINT_MAX == BIT16_MAX
|
|
||||||
typedef signed int Int16;
|
|
||||||
typedef unsigned int UInt16;
|
|
||||||
|
|
||||||
#elif USHRT_MAX == BIT16_MAX
|
|
||||||
typedef signed short Int16;
|
|
||||||
typedef unsigned short UInt16;
|
|
||||||
|
|
||||||
#elif UCHAR_MAX == BIT16_MAX
|
|
||||||
typedef signed char Int16;
|
|
||||||
typedef unsigned char UInt16;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error Unable to determine suitable data type for 16-bit integers.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if ULONG_MAX == BIT32_MAX
|
|
||||||
typedef signed long Int32;
|
|
||||||
typedef unsigned long UInt32;
|
|
||||||
|
|
||||||
#elif UINT_MAX == BIT32_MAX
|
|
||||||
typedef signed int Int32;
|
|
||||||
typedef unsigned int UInt32;
|
|
||||||
|
|
||||||
#elif USHRT_MAX == BIT32_MAX
|
|
||||||
typedef signed short Int32;
|
|
||||||
typedef unsigned short UInt32;
|
|
||||||
|
|
||||||
#elif UCHAR_MAX == BIT32_MAX
|
|
||||||
typedef signed char Int32;
|
|
||||||
typedef unsigned char UInt32;
|
|
||||||
|
|
||||||
#else
|
|
||||||
#error Unable to determine suitable data type for 32-bit integers.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* CYTOPLASM_INT_H */
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation files
|
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef CYTOPLASM_INT64_H
|
|
||||||
#define CYTOPLASM_INT64_H
|
|
||||||
|
|
||||||
/***
|
|
||||||
* @Nm Int64
|
|
||||||
* @Nd Fixed-width 64 bit integers.
|
|
||||||
* @Dd August 11, 2023
|
|
||||||
*
|
|
||||||
* .Pp
|
|
||||||
* ANSI C89 (or C99 for that matter) provides no required mechanism
|
|
||||||
* for 64 bit integers. Nevertheless, many compilers provide them as
|
|
||||||
* extensions. However, since it is not a gaurantee, and to be fully
|
|
||||||
* standards-compliant and thus portable, a platform-agnostic interface
|
|
||||||
* is required. This header provides such an interface. If the platform
|
|
||||||
* has a 64 bit integer type, that is used, and native operations are
|
|
||||||
* performed by C preprocessor macro expansion. Otherwise, a
|
|
||||||
* compatibility layer is provided, which implements 64-bit
|
|
||||||
* arithmetic on an array of 2 32-bit numbers which are provided by
|
|
||||||
* .Xr Int 3 .
|
|
||||||
* .Pp
|
|
||||||
* Note that 64-bit emulation is certainly not as performant as using
|
|
||||||
* native 64-bit operations, so whenever possible, the native
|
|
||||||
* operations should be preferred. However, since C provides no required
|
|
||||||
* 64 bit integer on 32-bit and less platforms, this API can be used as
|
|
||||||
* a "good enough" fallback mechanism.
|
|
||||||
* .Pp
|
|
||||||
* Also note that this implementation, both in the native and
|
|
||||||
* non-native forms, makes some assumptions:
|
|
||||||
* .Bl -bullet -width Ds
|
|
||||||
* .It
|
|
||||||
* When a cast from a larger integer to a smaller integer is performed,
|
|
||||||
* the upper bits are truncated, not the lower bits.
|
|
||||||
* .It
|
|
||||||
* Negative numbers are represented in memory and in registers in two's
|
|
||||||
* compliment form.
|
|
||||||
* .El
|
|
||||||
* .Pp
|
|
||||||
* This API may provide unexpected output if these assumptions are
|
|
||||||
* false for a given platform.
|
|
||||||
*
|
|
||||||
* @ignore-typedefs
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Int.h"
|
|
||||||
#include "UInt64.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifndef INT64_FORCE_EMULATED
|
|
||||||
|
|
||||||
#define BIT64_MAX 18446744073709551615UL
|
|
||||||
|
|
||||||
#if UINT_MAX == BIT64_MAX
|
|
||||||
typedef signed int Int64;
|
|
||||||
|
|
||||||
#define INT64_NATIVE
|
|
||||||
|
|
||||||
#elif ULONG_MAX == BIT64_MAX
|
|
||||||
typedef signed long Int64;
|
|
||||||
|
|
||||||
#define INT64_NATIVE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* ifndef INT64_FORCE_EMULATED */
|
|
||||||
|
|
||||||
#ifdef INT64_NATIVE
|
|
||||||
|
|
||||||
#define Int64Create(high, low) ((Int64) (((UInt64) (high) << 32) | (low)))
|
|
||||||
#define Int64Neg(x) (-(x))
|
|
||||||
|
|
||||||
#define Int64Low(a) ((UInt32) (a))
|
|
||||||
#define Int64High(a) ((UInt32) ((a) >> 32))
|
|
||||||
|
|
||||||
#define Int64Add(a, b) ((a) + (b))
|
|
||||||
#define Int64Sub(a, b) ((a) - (b))
|
|
||||||
#define Int64Mul(a, b) ((a) * (b))
|
|
||||||
#define Int64Div(a, b) ((a) / (b))
|
|
||||||
#define Int64Rem(a, b) ((a) % (b))
|
|
||||||
|
|
||||||
#define Int64Sll(a, b) ((a) << (b))
|
|
||||||
#define Int64Sra(a, b) ((a) >> (b))
|
|
||||||
|
|
||||||
#define Int64And(a, b) ((a) & (b))
|
|
||||||
#define Int64Or(a, b) ((a) | (b))
|
|
||||||
#define Int64Xor(a, b) ((a) ^ (b))
|
|
||||||
#define Int64Not(a) (~(a))
|
|
||||||
|
|
||||||
#define Int64Eq(a, b) ((a) == (b))
|
|
||||||
#define Int64Lt(a, b) ((a) < (b))
|
|
||||||
#define Int64Gt(a, b) ((a) > (b))
|
|
||||||
|
|
||||||
#define Int64Neq(a, b) ((a) != (b))
|
|
||||||
#define Int64Leq(a, b) ((a) <= (b))
|
|
||||||
#define Int64Geq(a, b) ((a) >= (b))
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define Int64Neg(x) (Int64Add(Int64Not(x), Int64Create(0, 1)))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The internal bit representation of a signed integer is identical
|
|
||||||
* to an unsigned integer, the difference is in the algorithms and
|
|
||||||
* the way the bits are interpreted.
|
|
||||||
*/
|
|
||||||
typedef UInt64 Int64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new signed 64 bit integer using the given high and low
|
|
||||||
* bits.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Create(UInt32, UInt32);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add two signed 64 bit integers together.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Add(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtract the second 64 bit integer from the first.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Sub(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiply two 64 bit integers together. The non-native version of
|
|
||||||
* this function uses the Russian Peasant method of multiplication,
|
|
||||||
* which should afford more performance than a naive multiplication by
|
|
||||||
* addition, but it is still rather slow and depends on the size of
|
|
||||||
* the integers being multiplied.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Mul(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divide the first 64 bit integer by the second and return the
|
|
||||||
* quotient. The non-native version of this function uses naive binary
|
|
||||||
* long division, which is slow, but gauranteed to finish in constant
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Div(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divide the first 64 bit integer by the second and return the
|
|
||||||
* remainder. The non-native version of this function uses naive binary
|
|
||||||
* long division, which is slow, but gauranteed to finish in constant
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Rem(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a left logical bit shift of a 64 bit integer. The second
|
|
||||||
* parameter is how many places to shift, and is declared as a regular
|
|
||||||
* integer because anything more than 64 does not make sense.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Sll(Int64, int);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a right arithmetic bit shift of a 64 bit integer. The second
|
|
||||||
* parameter is how many places to shift, and is declared as a regular
|
|
||||||
* integer because anything more than 64 does not make sense.
|
|
||||||
* .Pp
|
|
||||||
* Note that on platforms that use the native 64-bit implementation,
|
|
||||||
* this is technically implementation-defined, and may in fact be a
|
|
||||||
* logical shift instead of an arithmetic shift. Note that typically
|
|
||||||
* this operation is not performed on signed integers.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Sra(Int64, int);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise AND (&) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64And(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise OR (|) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Or(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise XOR (^) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Xor(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise NOT (~) of the provided 64 bit integer.
|
|
||||||
*/
|
|
||||||
extern Int64 Int64Not(Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if they are equal.
|
|
||||||
*/
|
|
||||||
extern int Int64Eq(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if the second operand is strictly
|
|
||||||
* less than the first.
|
|
||||||
*/
|
|
||||||
extern int Int64Lt(Int64, Int64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if the second operand is strictly
|
|
||||||
* greater than the first.
|
|
||||||
*/
|
|
||||||
extern int Int64Gt(Int64, Int64);
|
|
||||||
|
|
||||||
#define Int64Low(a) ((a).i[0])
|
|
||||||
#define Int64High(a) ((a).i[1])
|
|
||||||
|
|
||||||
#define Int64Neq(a, b) (!Int64Eq(a, b))
|
|
||||||
#define Int64Leq(a, b) (Int64Eq(a, b) || Int64Lt(a, b))
|
|
||||||
#define Int64Geq(a, b) (Int64Eq(a, b) || Int64Gt(a, b))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define INT64_STRBUF 65 /* Base 2 representation with '\0' */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a 64 bit integer to a string in an arbitrary base
|
|
||||||
* representation specified by the second parameter, using the provided
|
|
||||||
* buffer and length specified by the third and fourth parameters. To
|
|
||||||
* guarantee that the string will fit in the buffer, allocate it of
|
|
||||||
* size INT64_STRBUF or larger. Note that a buffer size smaller than
|
|
||||||
* INT64_STRBUF will invoke undefined behavior.
|
|
||||||
*/
|
|
||||||
extern size_t Int64Str(Int64, int, char *, size_t);
|
|
||||||
|
|
||||||
#endif /* CYTOPLASM_INT64_H */
|
|
|
@ -71,10 +71,10 @@
|
||||||
#include "HashMap.h"
|
#include "HashMap.h"
|
||||||
#include "Array.h"
|
#include "Array.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "Int64.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define JSON_DEFAULT -1
|
#define JSON_DEFAULT -1
|
||||||
#define JSON_PRETTY 0
|
#define JSON_PRETTY 0
|
||||||
|
@ -152,7 +152,7 @@ extern char * JsonValueAsString(JsonValue *);
|
||||||
* Encode a number as a JSON value that can be added to an object or
|
* Encode a number as a JSON value that can be added to an object or
|
||||||
* an array.
|
* an array.
|
||||||
*/
|
*/
|
||||||
extern JsonValue * JsonValueInteger(Int64);
|
extern JsonValue * JsonValueInteger(uint64_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unwrap a JSON value that represents a number. This function will
|
* Unwrap a JSON value that represents a number. This function will
|
||||||
|
@ -160,7 +160,7 @@ extern JsonValue * JsonValueInteger(Int64);
|
||||||
* misleading. Check the type of the value before making assumptions
|
* misleading. Check the type of the value before making assumptions
|
||||||
* about its value.
|
* about its value.
|
||||||
*/
|
*/
|
||||||
extern Int64 JsonValueAsInteger(JsonValue *);
|
extern uint64_t JsonValueAsInteger(JsonValue *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a floating point number as a JSON value that can be added
|
* Encode a floating point number as a JSON value that can be added
|
||||||
|
@ -181,7 +181,7 @@ extern double JsonValueAsFloat(JsonValue *);
|
||||||
* expressions as a JSON value that can be added to an object or an
|
* expressions as a JSON value that can be added to an object or an
|
||||||
* array.
|
* array.
|
||||||
*/
|
*/
|
||||||
extern JsonValue * JsonValueBoolean(int);
|
extern JsonValue * JsonValueBoolean(bool);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unwrap a JSON value that represents a boolean. This function will
|
* Unwrap a JSON value that represents a boolean. This function will
|
||||||
|
@ -189,7 +189,7 @@ extern JsonValue * JsonValueBoolean(int);
|
||||||
* misleading. Check the type of the value before making assumptions
|
* misleading. Check the type of the value before making assumptions
|
||||||
* about its type.
|
* about its type.
|
||||||
*/
|
*/
|
||||||
extern int JsonValueAsBoolean(JsonValue *);
|
extern bool JsonValueAsBoolean(JsonValue *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a special case that represents a JSON null. Because the
|
* This is a special case that represents a JSON null. Because the
|
||||||
|
@ -253,7 +253,7 @@ extern void JsonFree(HashMap *);
|
||||||
* or if the stream is NULL, the number of bytes that would have
|
* or if the stream is NULL, the number of bytes that would have
|
||||||
* been written.
|
* been written.
|
||||||
*/
|
*/
|
||||||
extern int JsonEncodeString(const char *, Stream *);
|
extern size_t JsonEncodeString(const char *, Stream *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize a JSON value as it would appear in JSON output. This is
|
* Serialize a JSON value as it would appear in JSON output. This is
|
||||||
|
@ -277,7 +277,7 @@ extern int JsonEncodeString(const char *, Stream *);
|
||||||
* or if the stream is NULL, the number of bytes that would have
|
* or if the stream is NULL, the number of bytes that would have
|
||||||
* been written.
|
* been written.
|
||||||
*/
|
*/
|
||||||
extern int JsonEncodeValue(JsonValue *, Stream *, int);
|
extern size_t JsonEncodeValue(JsonValue *, Stream *, int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a JSON object as it would appear in JSON output, writing it
|
* Encode a JSON object as it would appear in JSON output, writing it
|
||||||
|
@ -289,7 +289,7 @@ extern int JsonEncodeValue(JsonValue *, Stream *, int);
|
||||||
* or if the stream is NULL, the number of bytes that would have
|
* or if the stream is NULL, the number of bytes that would have
|
||||||
* been written.
|
* been written.
|
||||||
*/
|
*/
|
||||||
extern int JsonEncode(HashMap *, Stream *, int);
|
extern size_t JsonEncode(HashMap *, Stream *, int);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode a JSON object from the given input stream and parse it into
|
* Decode a JSON object from the given input stream and parse it into
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
* macros.
|
* macros.
|
||||||
*/
|
*/
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These values are passed into the memory hook function to indicate
|
* These values are passed into the memory hook function to indicate
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These functions operate on a queue structure that is opaque to the
|
* These functions operate on a queue structure that is opaque to the
|
||||||
|
@ -73,7 +74,7 @@ extern void QueueFree(Queue *);
|
||||||
* value indicating whether or not the push succeeded. Pushing items
|
* value indicating whether or not the push succeeded. Pushing items
|
||||||
* into the queue will fail if the queue is full.
|
* into the queue will fail if the queue is full.
|
||||||
*/
|
*/
|
||||||
extern int QueuePush(Queue *, void *);
|
extern bool QueuePush(Queue *, void *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pop an element out of the queue. This function returns NULL if the
|
* Pop an element out of the queue. This function returns NULL if the
|
||||||
|
@ -95,11 +96,11 @@ extern void * QueuePeek(Queue *);
|
||||||
/**
|
/**
|
||||||
* Determine whether or not the queue is full.
|
* Determine whether or not the queue is full.
|
||||||
*/
|
*/
|
||||||
extern int QueueFull(Queue *);
|
extern bool QueueFull(Queue *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether or not the queue is empty.
|
* Determine whether or not the queue is empty.
|
||||||
*/
|
*/
|
||||||
extern int QueueEmpty(Queue *);
|
extern bool QueueEmpty(Queue *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,11 +58,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a single random integer between 0 and the passed value.
|
* Generate a single random 32-bit integer between 0 and the
|
||||||
|
* passed value.
|
||||||
*/
|
*/
|
||||||
extern int RandInt(unsigned int);
|
extern uint32_t RandInt(uint32_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate the number of integers specified by the second argument
|
* Generate the number of integers specified by the second argument
|
||||||
|
@ -76,6 +78,6 @@ extern int RandInt(unsigned int);
|
||||||
* has to lock and unlock a mutex. It is therefore better to obtain
|
* has to lock and unlock a mutex. It is therefore better to obtain
|
||||||
* multiple random numbers in one pass if multiple are needed.
|
* multiple random numbers in one pass if multiple are needed.
|
||||||
*/
|
*/
|
||||||
extern void RandIntN(int *, size_t, unsigned int);
|
extern void RandIntN(uint32_t *, size_t, uint32_t);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_RAND_H */
|
#endif /* CYTOPLASM_RAND_H */
|
||||||
|
|
|
@ -39,21 +39,21 @@
|
||||||
* is a standard library header.
|
* is a standard library header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Int.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert UTF-16 into a Unicode codepoint.
|
* Convert UTF-16 into a Unicode codepoint.
|
||||||
*/
|
*/
|
||||||
extern UInt32 StrUtf16Decode(UInt16, UInt16);
|
extern uint32_t StrUtf16Decode(uint16_t, uint16_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a Unicode codepoint and encode it into a string buffer containing
|
* Take a Unicode codepoint and encode it into a string buffer containing
|
||||||
* between 1 and 4 bytes. The string buffer is allocated on the heap,
|
* between 1 and 4 bytes. The string buffer is allocated on the heap,
|
||||||
* so it should be freed when it is no longer needed.
|
* so it should be freed when it is no longer needed.
|
||||||
*/
|
*/
|
||||||
extern char * StrUtf8Encode(UInt32);
|
extern char * StrUtf8Encode(uint32_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Duplicate a null-terminated string, returning a new string on the
|
* Duplicate a null-terminated string, returning a new string on the
|
||||||
|
@ -87,7 +87,7 @@ extern char * StrConcat(size_t,...);
|
||||||
* string consists only of blank characters, as determined by
|
* string consists only of blank characters, as determined by
|
||||||
* .Xr isblank 3 .
|
* .Xr isblank 3 .
|
||||||
*/
|
*/
|
||||||
extern int StrBlank(const char *str);
|
extern bool StrBlank(const char *str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a string of the specified length, containing random
|
* Generate a string of the specified length, containing random
|
||||||
|
@ -124,6 +124,6 @@ extern char * StrLower(char *);
|
||||||
* function returns a boolean value indicating whether or not
|
* function returns a boolean value indicating whether or not
|
||||||
* strcmp() returned 0.
|
* strcmp() returned 0.
|
||||||
*/
|
*/
|
||||||
extern int StrEquals(const char *, const char *);
|
extern bool StrEquals(const char *, const char *);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_STR_H */
|
#endif /* CYTOPLASM_STR_H */
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
#include "Io.h"
|
#include "Io.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An opaque structure analogous to C's FILE pointers.
|
* An opaque structure analogous to C's FILE pointers.
|
||||||
|
@ -172,7 +174,7 @@ extern off_t StreamSeek(Stream *, off_t, int);
|
||||||
* .Xr feof 3
|
* .Xr feof 3
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
extern int StreamEof(Stream *);
|
extern bool StreamEof(Stream *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the stream for an error condition, returning a boolean value
|
* Test the stream for an error condition, returning a boolean value
|
||||||
|
@ -181,7 +183,7 @@ extern int StreamEof(Stream *);
|
||||||
* .Xr ferror 3
|
* .Xr ferror 3
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
extern int StreamError(Stream *);
|
extern bool StreamError(Stream *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the error condition associated with the given stream, allowing
|
* Clear the error condition associated with the given stream, allowing
|
||||||
|
|
|
@ -1,252 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person
|
|
||||||
* obtaining a copy of this software and associated documentation files
|
|
||||||
* (the "Software"), to deal in the Software without restriction,
|
|
||||||
* including without limitation the rights to use, copy, modify, merge,
|
|
||||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
|
||||||
* and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be
|
|
||||||
* included in all copies or portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
||||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
|
||||||
#ifndef CYTOPLASM_UINT64_H
|
|
||||||
#define CYTOPLASM_UINT64_H
|
|
||||||
|
|
||||||
/***
|
|
||||||
* @Nm UInt64
|
|
||||||
* @Nd Fixed-width 64 bit integers.
|
|
||||||
* @Dd August 11, 2023
|
|
||||||
*
|
|
||||||
* .Pp
|
|
||||||
* ANSI C89 (or C99 for that matter) provides no required mechanism
|
|
||||||
* for 64 bit integers. Nevertheless, many compilers provide them as
|
|
||||||
* extensions. However, since it is not a gaurantee, and to be fully
|
|
||||||
* standards-compliant and thus portable, a platform-agnostic interface
|
|
||||||
* is required. This header provides such an interface. If the platform
|
|
||||||
* has a 64 bit integer type, that is used, and native operations are
|
|
||||||
* performed by C preprocessor macro expansion. Otherwise, a
|
|
||||||
* compatibility layer is provided, which implements 64-bit
|
|
||||||
* arithmetic on an array of 2 32-bit numbers which are provided by
|
|
||||||
* .Xr Int 3 .
|
|
||||||
* .Pp
|
|
||||||
* Note that 64-bit emulation is certainly not as performant as using
|
|
||||||
* native 64-bit operations, so whenever possible, the native
|
|
||||||
* operations should be preferred. However, since C provides no required
|
|
||||||
* 64 bit integer on 32-bit and less platforms, this API can be used as
|
|
||||||
* a "good enough" fallback mechanism.
|
|
||||||
* .Pp
|
|
||||||
* Also note that this implementation, both in the native and
|
|
||||||
* non-native forms, makes some assumptions:
|
|
||||||
* .Bl -bullet -width Ds
|
|
||||||
* .It
|
|
||||||
* When a cast from a larger integer to a smaller integer is performed,
|
|
||||||
* the upper bits are truncated, not the lower bits.
|
|
||||||
* .It
|
|
||||||
* Negative numbers are represented in memory and in registers in two's
|
|
||||||
* compliment form.
|
|
||||||
* .El
|
|
||||||
* .Pp
|
|
||||||
* This API may provide unexpected output if these assumptions are
|
|
||||||
* false for a given platform.
|
|
||||||
*
|
|
||||||
* @ignore-typedefs
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Int.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifndef INT64_FORCE_EMULATED
|
|
||||||
|
|
||||||
#define BIT64_MAX 18446744073709551615UL
|
|
||||||
|
|
||||||
#if UINT_MAX == BIT64_MAX
|
|
||||||
/* typedef signed int Int64; */
|
|
||||||
typedef unsigned int UInt64;
|
|
||||||
|
|
||||||
#define UINT64_NATIVE
|
|
||||||
|
|
||||||
#elif ULONG_MAX == BIT64_MAX
|
|
||||||
/* typedef signed int Int64; */
|
|
||||||
typedef unsigned long UInt64;
|
|
||||||
|
|
||||||
#define UINT64_NATIVE
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* ifndef INT64_FORCE_EMULATED */
|
|
||||||
|
|
||||||
#ifdef UINT64_NATIVE
|
|
||||||
|
|
||||||
#define UInt64Create(high, low) (((UInt64) (high) << 32) | (low))
|
|
||||||
#define UInt64Low(a) ((UInt32) ((a) & 0x00000000FFFFFFFF))
|
|
||||||
#define UInt64High(a) ((UInt32) ((a) >> 32))
|
|
||||||
|
|
||||||
#define UInt64Add(a, b) ((a) + (b))
|
|
||||||
#define UInt64Sub(a, b) ((a) - (b))
|
|
||||||
#define UInt64Mul(a, b) ((a) * (b))
|
|
||||||
#define UInt64Div(a, b) ((a) / (b))
|
|
||||||
#define UInt64Rem(a, b) ((a) % (b))
|
|
||||||
|
|
||||||
#define UInt64Sll(a, b) ((a) << (b))
|
|
||||||
#define UInt64Srl(a, b) ((a) >> (b))
|
|
||||||
|
|
||||||
#define UInt64And(a, b) ((a) & (b))
|
|
||||||
#define UInt64Or(a, b) ((a) | (b))
|
|
||||||
#define UInt64Xor(a, b) ((a) ^ (b))
|
|
||||||
#define UInt64Not(a) (~(a))
|
|
||||||
|
|
||||||
#define UInt64Eq(a, b) ((a) == (b))
|
|
||||||
#define UInt64Lt(a, b) ((a) < (b))
|
|
||||||
#define UInt64Gt(a, b) ((a) > (b))
|
|
||||||
|
|
||||||
#define UInt64Neq(a, b) ((a) != (b))
|
|
||||||
#define UInt64Leq(a, b) ((a) <= (b))
|
|
||||||
#define UInt64Geq(a, b) ((a) >= (b))
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For platforms that do not have a native integer large enough to
|
|
||||||
* store a 64 bit integer, this struct is used. i[0] contains the low
|
|
||||||
* bits of integer, and i[1] contains the high bits of the integer.
|
|
||||||
* .Pp
|
|
||||||
* This struct should not be accessed directly, because UInt64 may not
|
|
||||||
* actually be this struct, it might be an actual integer type. For
|
|
||||||
* maximum portability, only use the functions defined here to
|
|
||||||
* manipulate 64 bit integers.
|
|
||||||
*/
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
UInt32 i[2];
|
|
||||||
} UInt64;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new unsigned 64 bit integer using the given high and low
|
|
||||||
* bits.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Create(UInt32, UInt32);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add two unsigned 64 bit integers together.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Add(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subtract the second 64 bit integer from the first.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Sub(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiply two 64 bit integers together. The non-native version of
|
|
||||||
* this function uses the Russian Peasant method of multiplication,
|
|
||||||
* which should afford more performance than a naive multiplication by
|
|
||||||
* addition, but it is still rather slow and depends on the size of
|
|
||||||
* the integers being multiplied.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Mul(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divide the first 64 bit integer by the second and return the
|
|
||||||
* quotient. The non-native version of this function uses naive binary
|
|
||||||
* long division, which is slow, but gauranteed to finish in constant
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Div(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Divide the first 64 bit integer by the second and return the
|
|
||||||
* remainder. The non-native version of this function uses naive binary
|
|
||||||
* long division, which is slow, but gauranteed to finish in constant
|
|
||||||
* time.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Rem(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a left logical bit shift of a 64 bit integer. The second
|
|
||||||
* parameter is how many places to shift, and is declared as a regular
|
|
||||||
* integer because anything more than 64 does not make sense.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Sll(UInt64, int);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a right logical bit shift of a 64 bit integer. The second
|
|
||||||
* parameter is how many places to shift, and is declared as a regular
|
|
||||||
* integer because anything more than 64 does not make sense.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Srl(UInt64, int);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise AND (&) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64And(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise OR (|) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Or(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise XOR (^) of the provided 64 bit integers.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Xor(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a bitwise NOT (~) of the provided 64 bit integer.
|
|
||||||
*/
|
|
||||||
extern UInt64 UInt64Not(UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if they are equal.
|
|
||||||
*/
|
|
||||||
extern int UInt64Eq(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if the second operand is strictly
|
|
||||||
* less than the first.
|
|
||||||
*/
|
|
||||||
extern int UInt64Lt(UInt64, UInt64);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform a comparison of the provided 64 bit integers and return a C
|
|
||||||
* boolean that is true if and only if the second operand is strictly
|
|
||||||
* greater than the first.
|
|
||||||
*/
|
|
||||||
extern int UInt64Gt(UInt64, UInt64);
|
|
||||||
|
|
||||||
#define UInt64Low(a) ((a).i[0])
|
|
||||||
#define UInt64High(a) ((a).i[1])
|
|
||||||
|
|
||||||
#define UInt64Neq(a, b) (!UInt64Eq(a, b))
|
|
||||||
#define UInt64Leq(a, b) (UInt64Eq(a, b) || UInt64Lt(a, b))
|
|
||||||
#define UInt64Geq(a, b) (UInt64Eq(a, b) || UInt64Gt(a, b))
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define UINT64_STRBUF 65 /* Base 2 representation with '\0' */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a 64 bit integer to a string in an arbitrary base
|
|
||||||
* representation specified by the second parameter, using the provided
|
|
||||||
* buffer and length specified by the third and fourth parameters. To
|
|
||||||
* guarantee that the string will fit in the buffer, allocate it of
|
|
||||||
* size UINT64_STRBUF or larger. Note that a buffer size smaller than
|
|
||||||
* UINT64_STRBUF will invoke undefined behavior.
|
|
||||||
*/
|
|
||||||
extern size_t UInt64Str(UInt64, int, char *, size_t);
|
|
||||||
|
|
||||||
#endif /* CYTOPLASM_UINT64_H */
|
|
|
@ -43,7 +43,6 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
#include "UInt64.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current timestamp in milliseconds since the Unix epoch. This
|
* Get the current timestamp in milliseconds since the Unix epoch. This
|
||||||
|
@ -61,7 +60,7 @@
|
||||||
* overflow before it even gets to this function, which will cause this
|
* overflow before it even gets to this function, which will cause this
|
||||||
* function to produce unexpected results.
|
* function to produce unexpected results.
|
||||||
*/
|
*/
|
||||||
extern UInt64 UtilServerTs(void);
|
extern uint64_t UtilTsMillis(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use
|
* Use
|
||||||
|
@ -70,7 +69,7 @@ extern UInt64 UtilServerTs(void);
|
||||||
* was an error getting the last modified time of a file. This is
|
* was an error getting the last modified time of a file. This is
|
||||||
* primarily useful for caching file data.
|
* primarily useful for caching file data.
|
||||||
*/
|
*/
|
||||||
extern UInt64 UtilLastModified(char *);
|
extern uint64_t UtilLastModified(char *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function behaves just like the system call
|
* This function behaves just like the system call
|
||||||
|
@ -86,7 +85,7 @@ extern int UtilMkdir(const char *, const mode_t);
|
||||||
* .Xr nanosleep 2
|
* .Xr nanosleep 2
|
||||||
* to make its usage much, much simpler.
|
* to make its usage much, much simpler.
|
||||||
*/
|
*/
|
||||||
extern int UtilSleepMillis(UInt64);
|
extern int UtilSleepMillis(uint64_t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function works identically to the POSIX
|
* This function works identically to the POSIX
|
||||||
|
@ -112,6 +111,6 @@ extern ssize_t UtilGetLine(char **, size_t *, Stream *);
|
||||||
* .Fn pthread_self
|
* .Fn pthread_self
|
||||||
* to a number.
|
* to a number.
|
||||||
*/
|
*/
|
||||||
extern UInt32 UtilThreadNo(void);
|
extern uint32_t UtilThreadNo(void);
|
||||||
|
|
||||||
#endif /* CYTOPLASM_UTIL_H */
|
#endif /* CYTOPLASM_UTIL_H */
|
||||||
|
|
Loading…
Reference in a new issue