Compare commits

..

1 Commits

Author SHA1 Message Date
04e4d07e99 wip
All checks were successful
Test and Deploy / test (push) Successful in 12s
Test and Deploy / docs (push) Has been skipped
2024-05-06 12:17:13 -07:00
49 changed files with 1451 additions and 714 deletions

View File

@ -0,0 +1,63 @@
---
name: Test and Deploy
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libbsd-dev cmake build-essential
- name: Build and test
run: |
mkdir build
cd build
cmake ..
make
./tests
docs:
runs-on: ubuntu-latest
if: gitea.ref == 'refs/heads/master'
timeout-minutes: 5
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install SSH client
run: |
sudo apt-get update
sudo apt-get install -y openssh-client
- name: Setup SSH
run: |
mkdir -p ~/.ssh
ssh-keyscan -H burkey.co >> ~/.ssh/known_hosts
echo "${{ secrets.BURKEY_CO_KEY}}" >> ~/.ssh/id_rsa
chmod -R 700 ~/.ssh
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_rsa
- name: Install mkdocs
run: |
pip install mkdocs
- name: Build documentation
run: |
mkdocs build
- name: Deploy documentation
run: |
ssh debian@burkey.co "rm -rf /var/www/docs/libflint"
ssh debian@burkey.co "mkdir -p /var/www/docs/libflint"
ssh debian@burkey.co "chmod 755 /var/www/docs/libflint"
scp -r ./site/* debian@burkey.co:/var/www/docs/libflint/

3
.gitignore vendored
View File

@ -5,7 +5,4 @@ compile_commands.json
site
libflint.so
test
tcptest
testrunner
.idea
netmanual

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
flint

91
.idea/editor.xml generated Normal file
View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="BackendCodeEditorSettings">
<option name="/Default/Housekeeping/GlobalSettingsUpgraded/IsUpgraded/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppClangFormat/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/EditorConfig/EnableClangFormatSupport/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_BINARY_EXPRESSIONS_CHAIN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_CALLS_CHAIN/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXPRESSION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_FOR_STMT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTIPLE_DECLARATION/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_TERNARY/@EntryValue" value="ALIGN_ALL" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_CLASS_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_BLANK_LINES_IN_CODE/@EntryValue" value="2" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/KEEP_USER_LINEBREAKS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CASE_FROM_SWITCH/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_COMMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INT_ALIGN_EQ/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SIMPLE_BLOCK_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_ARGS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COMMA_IN_TEMPLATE_PARAMS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_SEMICOLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_SEMICOLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_UNARY_OPERATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_ARRAY_ACCESS_BRACKETS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_METHOD_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_INITIALIZER_BRACES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPECIAL_ELSE_IF_TREATMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_CAST_EXPRESSION_PARENTHESES/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_BINARY_OPSIGN/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_TERNARY_OPSIGNS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TYPE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/OTHER_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CASE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DECLARATION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_FUNCTION_DEFINITION/@EntryValue" value="1" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_WHILE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_ELSE_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_CATCH_ON_NEW_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_INDENTATION/@EntryValue" value="All" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_ARGUMENT/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_EXTENDS_LIST/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_PARAMETER/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_ARGUMENT/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ALIGN_MULTILINE_TYPE_PARAMETER/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BLANK_LINES_AROUND_DECLARATIONS/@EntryValue" value="0" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_ACCESS_SPECIFIERS_FROM_CLASS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_CLASS_MEMBERS_FROM_ACCESS_SPECIFIERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/LINE_BREAK_AFTER_COLON_IN_MEMBER_INITIALIZER_LISTS/@EntryValue" value="ON_SINGLE_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/MEMBER_INITIALIZER_LIST_STYLE/@EntryValue" value="DO_NOT_CHANGE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/PLACE_NAMESPACE_DEFINITIONS_ON_SAME_LINE/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_COLON_IN_BITFIELD_DECLARATOR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_EXTENDS_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_FOR_COLON/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_FOR_COLON/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_AFTER_REF_IN_DATA_MEMBERS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_DATA_MEMBERS/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_PTR_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_REF_IN_ABSTRACT_DECL/@EntryValue" value="true" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_BEFORE_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_DECLARATION_PARENTHESES/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_BLOCKS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_EMPTY_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_ARGS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/SPACE_WITHIN_TEMPLATE_PARAMS/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_INVOCATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_INVOCATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_AFTER_DECLARATION_LPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_BEFORE_DECLARATION_RPAR/@EntryValue" value="false" type="bool" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_ARGUMENTS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/WRAP_PARAMETERS_STYLE/@EntryValue" value="WRAP_IF_LONG" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/BREAK_TEMPLATE_DECLARATION/@EntryValue" value="LINE_BREAK" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/NAMESPACE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/FREE_BLOCK_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INVOCABLE_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue" value="END_OF_LINE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INITIALIZER_BRACES/@EntryValue" value="END_OF_LINE_NO_SPACE" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_STYLE/@EntryValue" value="Space" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/INDENT_SIZE/@EntryValue" value="4" type="int" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/CONTINUOUS_LINE_INDENT/@EntryValue" value="Double" type="string" />
<option name="/Default/CodeStyle/CodeFormatting/CppFormatting/TAB_WIDTH/@EntryValue" value="4" type="int" />
</component>
</project>

2
.idea/libfputs.iml generated Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/libfputs.iml" filepath="$PROJECT_DIR$/.idea/libfputs.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -2,10 +2,6 @@ cmake_minimum_required(VERSION 3.17)
project(flint C)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
add_compile_definitions(flint __USE_XOPEN_EXTENDED)
endif()
set(CMAKE_C_STANDARD 99)
include_directories(include)
@ -21,8 +17,6 @@ set(SOURCES
src/utility.c
src/crypto.c
src/parsing.c
src/network.c
src/memory.c
)
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Darwin"))
@ -32,7 +26,7 @@ else()
endif()
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
target_link_libraries(flint pthread bsd)
target_link_libraries(flint bsd)
endif()
if(${CMAKE_PROJECT_NAME} STREQUAL flint)
@ -40,17 +34,8 @@ if(${CMAKE_PROJECT_NAME} STREQUAL flint)
target_include_directories(tests PRIVATE include)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_link_libraries(tests flint pthread bsd)
target_link_libraries(tests flint bsd)
else()
target_link_libraries(tests flint pthread)
endif()
add_executable(netmanual tests/netmanual.c)
target_include_directories(netmanual PRIVATE include)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
target_link_libraries(netmanual flint pthread bsd)
else()
target_link_libraries(netmanual flint pthread)
target_link_libraries(tests flint)
endif()
endif()

View File

@ -1,13 +1,32 @@
CMAKE_OPTS=-DCMAKE_EXPORT_COMPILE_COMMANDS=1
.PHONY : clean
all:
mkdir -p build
cd build && \
cmake ${CMAKE_OPTS} .. && \
$(MAKE) && \
cp compile_commands.json ..
CFLAGS = -std=c99 -Iinclude -pedantic -Wall -Wextra
LDFLAGS = -fPIC -shared
TARGET = libflint.so
SRC != ls src/*.c
OBJ = $(SRC:./src/$.c=./obj/%.o)
PREFIX = $(DESTDIR)/usr/local
LIBDIR = $(PREFIX)/lib
all: $(TARGET)
$(TARGET): $(OBJ)
cc $(CFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJ)
./obj/%.o: ./src/%.c
cc $(CFLAGS) -c $< -o $@
install: $(TARGET)
cp $(TARGET) $(LIBDIR)
uninstall:
rm -f $(LIBDIR)/$(TARGET)
clean:
rm -rf build
rm -f compile_commands.json
rm -f $(TARGET)
rm -f test
test:
cc $(CFLAGS) -o test tests/tests.c src/*.c

View File

@ -4,23 +4,7 @@ My personal library of common C data structures and algorithms. Supports Linux,
## Documentation
Extensive documentation can be found [here](https://wiki.burkey.co/doku.php?id=libflint:start). You can also check out `tests/tests.c` to
see example usage from most of the library's API.
## Building
`libflint` requires Cmake to be built. It can then be built using either `cmake` or `make` with the provided build files. The `Makefile` is a wrapper around Cmake for Makefile compatibility.
### Cmake
```cmake
# If libflint is in ./lib/libflint
add_subdirectory(lib/libflint)
# when building target...
target_include_directories(${TARGET} PRIVATE lib/libflint/include)
target_link_libraries(${TARGET} PRIVATE flint )
```
Extensive documentation can be found [here](https://fputs.com/docs/libflint/)
## Requirements

10
build.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh -e
# For building outside of CLion
mkdir -p build
cd build
cmake ..
make
cp compile_commands.json ..
cd

View File

@ -1,17 +0,0 @@
#!/usr/bin/env sh
set -e
CFLAGS="-I./include -I/usr/local/include"
rm -f compile_commands.json
for f in $(find ./src -type f | grep -v macos); do
n=$(echo $f | grep -o '[^/]*$' | sed 's/c$/json/')
cc -MJ $n $CFLAGS -c $f
done
rm *.o
sed -e '1s/^/[/' -e '$s/,$/]/' *.json > compile_commands.out
rm *.json
mv compile_commands.out compile_commands.json

203
docs/binarytree.md Normal file
View File

@ -0,0 +1,203 @@
# binarytree
Binary tree with standard leaf operations
## Usage
Create the tree. The user is responsible for memory management of the `BinTree` struct.
```c
BinTree *tree = malloc(sizeof(BinTree));
```
After the tree is created, init it. The second argument on `bintree_init()` is an optional memory freeing function pointer
with signature `void (*destroy)(void *data)`. Use `free()` from the stdlib if you are creating the data with `malloc()`.
If allocation of your data is more complex, you can pass your own memory deallocation function as long as it fits the
signature.
In this example, we are passing `NULL` because all memory will be stack allocated.
```c
bintree_init(tree, NULL);
int root = 0;
int l1 = 1;
int l2 = 2;
int r1 = 12;
int r2 = 200;
```
Next lets insert our data into the tree. The insert functions signature is `bintree_ins_...(tree, parent, data)`. If you
are inserting data at the root of the tree, you may use either `bintree_ins_left()` or `bintree_ins_right()` as long as
`NULL` is passed as the parent argument.
```c
bintree_ins_left(tree, NULL, &root);
bintree_ins_left(tree, tree->root, &l1);
bintree_ins_left(tree, tree->root->left, &l2);
bintree_ins_right(tree, tree->root->left, &r2);
bintree_ins_right(tree, tree->root, &r1);
bintree_ins_right(tree, tree->root->right, &r2);
bintree_ins_left(tree, tree->root->right, &l1);
```
We can use `bintree_debug_print(tree)` to print a graphical representation of the tree to `stdout`
```plaintext
└──0
├──1
│ ├──2
│ └──200
└──12
├──1
└──200
```
To cleanup the tree, first destroy the nodes. If you passed a deallocation function, it will be called on
the data member of each node before the node itself is freed. `bintree_destroy()` does not free the tree itself, just the
nodes inside of it, hence we must also call `free()` on the tree.
```c
bintree_destroy(tree);
free(tree);
tree = NULL;
```
Here is the entire example:
```c
BinTree *tree = malloc(sizeof(BinTree));
bintree_init(tree, NULL);
int root = 0;
int l1 = 1;
int l2 = 2;
int r1 = 12;
int r2 = 200;
bintree_ins_left(tree, NULL, &root);
bintree_ins_left(tree, tree->root, &l1);
bintree_ins_left(tree, tree->root->left, &l2);
bintree_ins_right(tree, tree->root->left, &r2);
bintree_ins_right(tree, tree->root, &r1);
bintree_ins_right(tree, tree->root->right, &r2);
bintree_ins_left(tree, tree->root->right, &l1);
bintree_debug_print(tree);
bintree_destroy(tree);
free(tree);
tree = NULL;
```
## Structs
### BinTree
Binary tree struct
```c
typedef struct {
int size;
int (*compare)(const void *a, const void *b);
void (*destroy)(void *data);
struct BinTreeNode *root;
} BinTree;
```
Members:
- `size`: How many nodes the tree contains
- `compare`: Comparison function between data in two nodes. Currently not used for anything
- `destroy`: Optional deallocation function for data inside a node. Typical usage is `NULL` for stack allocated data and `free()` for data created with `malloc()`
- `root`: The root node of the tree
### BinTreeNode
Node of the tree
```c
typedef struct BinTreeNode {
void *data;
struct BinTreeNode *left;
struct BinTreeNode *right;
} BinTreeNode;
```
Members:
- `data`: void pointer to data the node contains
- `left`: left facing leaf of the node
- `right`: right facing leaf of the node
## Functions
### bintree_init
Initialize the binary tree. User is responsible for freeing memory with `bintree_destroy()`.
```c
void bintree_init(BinTree *tree, void (*destroy)(void *data))
```
### bintree_destroy
Destroys the nodes inside a tree and calls the deallaction function on the data if one was provided. Does not deallocate
the tree itself, that is left to the user.
```c
void bintree_destroy(BinTree *tree)
```
### bintree_ins_left
Creates a new node containing `data` and inserts it as the left child of `node`.
```c
int bintree_ins_left(BinTree *tree, BinTreeNode *node, void *data)
```
### bintree_ins_right
Creates a new node containing `data` and inserts it as the right child of `node`.
```c
int bintree_ins_right(BinTree *tree, BinTreeNode *node, void *data)
```
### bintree_rem_left
Removes and deallocates the left child node of `node`. Calls the deallocation function on the data if one was provided.
```c
void bintree_rem_left(BinTree *tree, BinTreeNode *node)
```
### bintree_rem_right
Removes and deallocates the right child node of `node`. Calls the deallocation function on the data if one was provided.
```c
void bintree_rem_right(BinTree *tree, BinTreeNode *node)
```
### bintree_debug_print
Prints a representation of the tree to stdout. Gets very messy with large trees.
```c
void bintree_debug_print(BinTree *tree)
```
### bintree_is_eob
Utility macro that checks if the node is the End Of Branch.
```c
#define bintree_is_eob(node) ((node) == NULL)
```
### bintree_is_leaf
Utility macro that checks if a node has children.
```c
#define bintree_is_leaf(node) ((node)->left == NULL && (node)->right == NULL)
```

8
docs/bool.md Normal file
View File

@ -0,0 +1,8 @@
# bool
Macro representation of truthy values
```c
#define LFTRUE 1
#define LFFALSE 0
```

107
docs/crypto.md Normal file
View File

@ -0,0 +1,107 @@
# crypto
Cryptographic tools
Any functions that return string representations of bytes in hexadecimal format will
always be formatted with no leading `0x` and lower case letters
## Functions
### b64_encode
Encodes an `unsigned char *` into base64. User is responsible for freeing the
`char *` that is returned.
```c
char *b64_encode(const unsigned char *s, size_t sz);
```
### b64_decode
Decodes a base64 encoded set of bytes into an `unsigned char *`. User is responsible
for freeing the `unsigned char *` that is returned. `decode_sz` is an optional argument
in case you need to know the size of the decoded data, otherwise you can just pass `NULL`.
```c
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz);
```
### hex_encode
Encodes an array of bytes into a string in hex representation. For example, converts
`[0xDE, 0xAD, 0xBE, 0xEF]` into `"deadbeef"`. User is responsible for freeing the returned string
```c
const char *hex_encode(const unsigned char *hex, size_t sz);
// Example
unsigned char h[4] = {
0xde, 0xad, 0xbe, 0xef
};
const char *s = hex_encode(h, 4);
assert(strcmp(s, "deadbeef") == 0);
free(s);
```
### hex_decode
Decodes a string of characters representing hexadecimal bytes into an array of `unsigned char`.
Characters can be in upper or lower case, and can start with a leading `0x` or not.
For example, converts `"DEADBEEF"` into `[0xde, 0xad, 0xbe, 0xef]`. User is reponsible for the
freeing of the returned byte array
```c
unsigned char *hex_decode(const char *orig, size_t *sz);
// Example
unsigned char *s = hex_decode("DEADBEEF", &s_sz);
unsigned char h[4] = {
0xDE, 0xAD, 0xBE, 0xEF
};
for (size_t i = 0; i < 4; ++i) {
assert(s[i] == h[i]);
}
free(s);
```
### hex_to_str
Converts an array of `unsigned char` into a string based on the ASCII values of each byte. User is
responsible for freeing the returned string.
```c
const char *hex_to_str(const unsigned char *hex, size_t sz);
```
### repeating_key_xor
Performs a repeating-key XOR encryption on an array of bytes. User is responsible for freeing the returned array
```c
const unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz);
```
### repeating_key_xor_s
Performs a repeating-key XOR encryption on a string. Returns the encrypted string as an array of bytes. User is
responsible for freeing the returned array
```c
const unsigned char *repeating_key_xor_s(const char* s, const char* key);
```
### hamming_distance
Calculates the Hamming Distance (the number of differing bits) between two arrays of unsigned bytes
```c
unsigned int hamming_distance(unsigned char *a, unsigned char *b);
```
### hamming_distance_s
Calculates the Hamming Distance (the number of differing bits) between two strings
```c
unsigned int hamming_distance_s(const char *a, const char *b);
```

BIN
docs/flinty.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

25
docs/index.md Normal file
View File

@ -0,0 +1,25 @@
# libflint
`libflint` is a library of common C data structures and algorithms, designed to be as agnostic as possible for its
users. Over time, it has become my personal library of reusable C code.
## Requirements
### Linux
Requires `libbsd`. This should be available on all major Linux distros.
### macOS, OpenBSD, FreeBSD
Requires no extra dependencies
## Memory Management
The parts of this library that create data structures pass all responsibility of memory management to the user. This
is clearly documented in the individual module's documentation.
## Why the name 'libflint'?
`libflint` is named after my dog Flint, who passed away in 2021. I miss you buddy.
![flint](flinty.jpg)

103
docs/input.md Normal file
View File

@ -0,0 +1,103 @@
# input
I/O module to assist with consuming data from files
## Functions
### get_binary
Reads a file at `path` and returns the contents as a char* buffer. The `fsz` parameter stores the length of the
returned array. The buffer is allocated inside the function, so the user is responsible for freeing it when finished.
```c
char *get_binary(const char *path, size_t *fsz);
/* Usage */
size_t fsz = 0;
char *buf = get_binary("/home/evan/binfile", &fsz);
free(buf);
```
### get_input
Reads a file at `path` and returns the contents as a single string. The string is allocated inside the function and
the user is responsible for freeing it when finished.
```c
unsigned char *get_input(const char *path);
/* Usage */
char *str = get_input("/home/evan/textfile");
free(str);
```
### get_lines
Reads a file at `path` and returns the contents as an array of strings. The newline character `\n` is used as the
delimiter to determine where the file is split. The user is responsible for cleaning up the memory using `del_lines()`.
`lsz` is set to the number of lines in the array.
```c
char **get_lines(const char *path, size_t *lsz);
/* Usage */
size_t sz = 0;
char **lines = get_lines("/home/evan/textfile", &sz);
for (size_t i = 0; i < sz; i++) {
printf("%s\n", lines[i]);
}
del_lines(lines);
```
### del_lines
Frees all memory used by `get_lines()`
```c
void del_lines(char **lines);
```
### get_ints
Reads a file at `path` and returns the contents as an array of integers. The file is assumed to be a newline seperated
list of integers and nothing else.
The newline character `\n` is used as the delimiter to determine where the file is split. The user is responsible for
cleaning up the memory using `free()`. `lsz` is set to the number of lines in the array.
```c
int *get_ints(const char *path, size_t *lsz);
/* Usage */
int *nums = get_ints("/home/evan/intfile");
for (size_t i = 0; i < sz; i++) {
printf("%d\n", nums[i]);
}
free(nums);
```
### split
Takes a string `s` and splits it into an array of strings based on the delimiter. `s` is left unchanged. The user is
responsible for cleaning up the memory of the split using `del_split()`. `sp_sz` is set to the size of the split.
```c
char **split(char *s, size_t *lsz, const char *delim)
/* Usage */
size_t sp_sz = 0;
char **sp = split("Split on whitespace", &sp_sz, " ");
printf("%s\n", sp[0]); // Prints "Split"
```
### del_split
Frees all memory used by `split()`. Just like `split`, it does not touch the original string
```c
void del_split(char **sp);
/* Usage */
size_t sp_sz = 0;
char **sp = split("Delete Me!", &sp_sz, " ");
void del_split(sp);
```

230
docs/linkedlist.md Normal file
View File

@ -0,0 +1,230 @@
# linkedlist
A dual sided linked list structure. Used as the foundation for many other modules in `libflint`
## Usage
Create the list. The user is responsible for memory management of the `List` struct.
```c
List *list = malloc(sizeof(List));
```
After the tree is created, init it. The second argument on `bintree_init()` is an optional memory freeing function pointer
with signature `void (*destroy)(void *data)`. Use `free()` from the stdlib if you are creating the data with `malloc()`.
If allocation of your data is more complex, you can pass your own memory deallocation function as long as it fits the
signature.
In this example, we are passing `NULL` because all memory will be stack allocated.
```c
ll_init(list, NULL);
int i = 1;
int j = 2;
int k = 4;
```
Next, insert data into the list. Data can be inserted from either side of a node.
```c
ll_ins_next(list, list->head, (void *) &i);
ll_ins_next(list, list->tail, (void *) &j);
ll_ins_next(list, list->tail, (void *) &k);
/* List is now 1 2 4 */
```
Lists can have a node removed by either targeting the node directly or removing a node pointed to by the head or tail of
another node. The user is responsible for the memory management of the data inside the node, which is why a `void*` must
be supplied to hold the data. Since in this example our memory is stack allocated, we don't need to worry about freeing
the `void*` but one must still be supplied for the function to work.
```c
/* List is 1 2 4 */
/* node is the 2nd node in the list with value 2 */
ListNode *node = list->head;
/* void pointer to the data inside of the node */
void *data;
ll_remove(list, node, &data);
/* List is now 1 4 */
printf("Removed: %d\n", *((int *) data));
/* Prints "2" */
```
Here is an alternative example using `ll_remove_next()` instead of `ll_remove()`
```c
/* node is the 2nd node in the list with value 2 */
ListNode *node = list->head;
void *data; /* void pointer to the data inside of the node */
ll_remove_next(list, node, &data);
/* List is now 1 2 */
printf("Removed: %d\n", *((int *) data));
/* Prints "4" */
```
To destroy the list, first call `ll_destroy()` to free the nodes in the list and optionally run the destroy function
against the data stored in the list. Since this example is stack allocated and we passed `NULL` when creating the
list, no destroy function is run against the memory in the nodes. The list itself must be deleted with `free()`
```c
ll_destroy(list);
free(list);
```
Complete example:
```c
List *list = malloc(sizeof(List));
ll_init(list, NULL);
int i = 1;
int j = 2;
int k = 4;
ll_ins_next(list, list->head, (void *) &i);
ll_ins_next(list, list->tail, (void *) &j);
ll_ins_next(list, list->tail, (void *) &k);
printf("List: ");
print_ll(list);
void *data;
ll_remove_next(list, list->head, &data);
printf("List: ");
print_ll(list);
printf("Removed: %d\n", *((int *) data));
ll_destroy(list);
free(list);
```
## Structs
### List
Double ended linked list struct
```c
typedef struct {
size_t size;
void (*destroy)(void *data);
int (*match)(const void *a, const void *b);
struct ListNode *head;
struct ListNode *tail;
} List;
```
Members:
- `size`: How many nodes are in the list
- `destroy`: Optional deallocation function for member data. Use `NULL` if data is stack allocated
- `match`: Comparison function between data inside two nodes. This is not used by `List` itself, but is used in structures built on top of `List`
- `head`: Pointer to the `ListNode` at the head of the list
- `tail`: Pointer to the `ListNode` at the tail of the list
### ListNode
Node of the list
```c
typedef struct ListNode {
void *data;
struct ListNode *next;
struct ListNode *prev;
} ListNode;
```
Members:
- `data`: void pointer to the member data in the node
- `next`: Pointer to the `ListNode` before this node in the list
- `prev`: Pointer to the `ListNode` after this node in the list
## Functions
### ll_init
Initialize the list. User is responsible for creating the initial `List` structure and freeing memory with `ll_destroy()`. `destroy` is a deallocation function for the members of `List`, pass `NULL` if the memory is stack-allocated
```c
void ll_init(List *list, void (*destroy)(void *data));
/* Usage */
List *list = malloc(sizeof(Stack));
// Pass NULL for stack-allocated memory
ll_init(list, NULL);
// Pass free or a custom freeing function for heap allocated memory
ll_init(list, free);
```
### ll_destroy
Destroys the nodes inside a list and calls the deallocation funciton on the data if one was provided. Does not destroy the list itself, that is left up to the user.
```c
void ll_destroy(List *list);
```
### ll_ins_next
Creates a new node containing `data` and inserts it after `node`.
```c
int ll_ins_next(List *list, ListNode *node, const void *data);
```
### ll_ins_prev
Creates a new node containing `data` and inserts it before `node`.
```c
int ll_ins_prev(List *list, ListNode *node, const void *data);
```
### ll_remove
Removes and deallocates the node pointed to by `node`. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove()`
```c
int ll_remove(List *list, ListNode *node, void **data);
```
### ll_remove_next
Removes and deallocates the node pointed to by `node`'s `tail` pointer. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove_next()`
```c
int ll_remove_next(List *list, ListNode *node, void **data);
```
### ll_remove_prev
Removes and deallocates the node pointed to by `node`'s `head` pointer. The user is responsible for managing the contained data's memory,
as such the `destroy` function is **not** run by `ll_remove_prev()`
```c
int ll_remove_prev(List *list, ListNode *node, void **data);
```
## Macros
### LL_ITER
A utility macro that helps with iterating over an entire list. A `ListNode` pointer named `node` is created as part of
this macro and can be used to access the current node in the iteration, so be careful your own variable naming if you
intend to use `LL_ITER`.
```c
#define LL_ITER(list) for(ListNode *node = (list)->head; node != NULL; node = node->next)
/* Example with list of strings */
for LL_ITER(list) {
printf("%s\n", (char *)(node->data));
}
```

72
docs/macos.md Normal file
View File

@ -0,0 +1,72 @@
# macOS
Platform-specific code for macOS. Everything in this module, including the headers, is wrapped in the following
preprocessor macro
```c
#if defined(__APPLE__) || defined(__MACH__)
/*
... code ...
*/
#endif /* defined(__APPLE__) || defined(__MACH__) */
```
## Structs
### ProcessData
ProcessData is a struct that tracks cpu and memory usage of a process. It needs to be regularly updated with calls to
`update_process()` in order to provide accurate information
```c
typedef struct {
double total_user_time;
double total_kernel_time;
double last_total_consumed;
double percent_cpu;
uint64_t virtual_memory;
uint64_t resident_memory;
time_t timestamp;
time_t last_timestamp;
} ProcessData;
```
## Functions
## new_ProcessData
Returns a pointer to a `ProcessData` struct.
```c
ProcessData *new_ProcessData();
```
## update_process
Updates a `ProcessData` struct. This should be called in a loop or at specific intervals to measure proper usage
data. An example is below
```c
int update_process(pid_t pid, ProcessData *proc);
/* Example */
pid_t pid = getpid();
ProcessData *pd = new_ProcessData();
for (int i = 0; i < 10; i++) {
update_process(pid, pd);
printf("CPU: %.2f\n", pd->percent_cpu);
sleep(1);
}
free(pd);
```
## reallocarray
reallocarray is reimplemented for macOS because Apple doesn't expose their implementation. This is taken straight
from the OpenBSD source
```c
void *reallocarray(void *optr, size_t nmemb, size_t size);
```

74
docs/math.md Normal file
View File

@ -0,0 +1,74 @@
# math
General math functions
## Functions
## max_int
Return the maximum integer between `int a` and `int b`
```c
int max_int(int a, int b);
```
## min_int
Return the minimum integer between `int a` and `int b`
```c
int min_int(int a, int b);
```
## clamp_int
Clamps an integer between a high and low value
```c
int clamp_int(int i, int low, int high);
```
## binstr_to_int
Converts a string representing a binary number into an integer. Supports underscores as spacing
```c
int binstr_to_int(const char *s);
/* Usage */
int a = binstr_to_int("10011101");
int b = binstr_to_int("1001_1101_0010_1011");
```
## bresenham
Uses bresenham's line algorithim to generate a line in 2D space.
Returns a pointer to an array of `Point`.
The `sz` parameter holds the size of the array.
```c
Point *bresenham(int x0, int y0, int x1, int y1, size_t *sz);
```
## bresenham_p
Works the same as `bresenham()` but uses the `Point` struct instead of `int`
```c
Point *bresenham_p(Point p1, Point p2, size_t *sz);
```
## Comparison Functions
Comparison functions to compare two items. These functions must return `1` if `a > b`, `-1` if
`a < b`, or `0` if `a == b`. This follows the pattern defined by `compar` functions in the C standard
library, making these usuable in the standard sorting functions like `qsort`
```c
int compar_int(const void *a, const void *b);
int compar_char(const void *a, const void *b);
// Example
qsort(arr, arr_sz, sizeof(int), compar_int);
```

14
docs/parsing.md Normal file
View File

@ -0,0 +1,14 @@
# parsing
String parsing tools
## Functions
### simple_english_scoring
Scores a string based on a simple ETAOIN SHRDLU scale. A simple, somewhat accurate way to determine if a string is
English.
```c
int simple_english_scoring(const char *s);
```

3
docs/set.md Normal file
View File

@ -0,0 +1,3 @@
# set
Coming soon

74
docs/stack.md Normal file
View File

@ -0,0 +1,74 @@
# stack
LIFO (last in first out) stack structure
## Structs
`Stack` is a linked list with stack-based operations available
```c
#define Stack List
```
## Functions
### stack_init
Intializes the stack. The user is responsible for creating the initial `Stack` structure and freeing memory with `stack_destroy()`. `destroy` is a deallocation function for the members of `Stack`, pass `NULL` if the memory is stack-allocated
```c
void stack_init(Stack *stack, void (*destroy)(void *data));
/* Usage */
Stack *stack = malloc(sizeof(Stack));
// Pass NULL for stack-allocated memory
stack_init(stack, NULL);
// Pass free or a custom freeing function for heap allocated memory
stack_init(stack, free);
```
### stack_destroy
Destroys the nodes inside a `Stack` and calls the deallocation funciton on the data if one was provided. Does not destroy the list itself, that is left up to the user.
```c
void stack_destroy(Stack *stack);
```
### stack_push
Push a new element onto the top of the stack
```c
int stack_push(Stack *stack, void *data);
```
### stack_peek
Returns a `void *` to the top element of the stack. Does not remove the element
```c
void *stack_peek(Stack *stack);
/* Usage */
// stack: 1 2 3
int *t = (int*)stack_peek(stack);
assert(*t == 3);
// stack: 1 2 3
```
### stack_pop
Returns a `void *` to the top element of the stack and removes the element
```c
int stack_pop(Stack *stack, void **data);
/* Usage */
// stack: 1 2 3
int *t = (int*)stack_peek(stack);
assert(*t == 3);
// stack: 1 2
```

46
docs/string.md Normal file
View File

@ -0,0 +1,46 @@
# string
C string helpers
## Functions
### find_substrings
Finds the indicies of all locations of the given needle in the haystack. `substrings` is an array of `size_t` indicies that
the substring is found at. This function allocates the memory for `substrings` and memory cleanup is managed by the user.
`num_substrings` is a pointer to a pre-allocated `size_t` that will be modified to contain the number of found substrings
and subsequently the size of `substrings`.
If no substrings are found, `substrings` will not be allocated and left set to `NULL`, `num_substrings` will be `0`, and
the function will return `0`.
Returns 0 if the function is successful. Returns a non-zero value if there is an error.
```c
int find_substrings(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings);
/* Usage */
const char* haystack = "One two three two";
const char* needle = "two";
size_t subs_sz = 0;
size_t *subs = NULL;
size_t *subs = find_substrings(haystack, needle, &subs_sz, &subs);
// subs: [ 4, 14 ]
// subs_sz: 2
free(subs);
```
### substr
Extracts a substring at a specific index and length. This function returns a copy of the substring in a heap allocated
buffer that the user is responsible for freeing. Returns `NULL` if there is an error.
```c
const char* substr(const char* str, size_t idx, size_t len);
/* Usage */
const char *s = substr("One two three", 4, 3);
assert(strcmp(s, "two") == 0);
free(s);
```

16
docs/utility.md Normal file
View File

@ -0,0 +1,16 @@
# utility
Utility code that does not fit anywhere else
## Structs
### Point
Representation of a point on a two dimensional grid
```c
typedef struct {
int x;
int y;
} Point;
```

164
docs/vector.md Normal file
View File

@ -0,0 +1,164 @@
# vector
Simple type-agnostic dynamic array
## Structs
### Vector
Vector struct
```c
typedef struct Vector {
size_t capacity;
size_t length;
void **elements;
void (*destroy)(void *data);
} Vector;
```
Members:
- `capacity`: The size of `elements` in memory
- `length`: The number of real elements stored in the backing `elements` array
- `elements`: The dynamic array of `void *` that holds the vector's members
- `destroy`: Optional deallocation function for data inside a node. Typical usage is `NULL` for stack allocated data and `free()` for data created with `malloc()`
## Functions
### vec_init
Initialize the vector with a default capacity of 2. User is responsible for freeing elements of the vector with `vec_destroy()`. Returns a non-zero integer if there is an error
```c
int vec_init(Vector *vec, void (*destroy)(void *data));
```
### vec_init_with_capacity
Initialize the vector with a user-specified capacity. User is responsible for freeing elements of the vector with `vec_destroy()`. Returns a non-zero integer if there is an error
```c
int vec_init_with_capacity(Vector *vec, void (*destroy)(void *data), size_t cap);
```
### vec_destroy
Frees the underlying array inside a `Vector`. If `destroy` was provided when creating the vector, then it is called against each element in the array before the array is freed. Does not destroy the vector itself, that is left up to the user
```c
void vec_destroy(Vector *vec);
/* Usage */
vec_destroy(vec);
free(vec);
```
### vec_insert
Insert `data` into the vector at a specified index. Any elements at that array and beyond will be moved up to make room. Returns a non-zero integer if there is an error
```c
int vec_insert(Vector *vec, void *data, size_t index);
/* Usage */
// vec: 1 2 3 4
int i = 99;
vec_insert(vec, &i, 2);
// vec: 1 2 99 3 4
```
### vec_push
Insert `data` at the end of the vector. Returns a non-zero integer if there is an error
```c
int vec_push(Vector *vec, void *data);
/* Usage */
// vec: 1 2 3
int *i = malloc(sizeof(int));
*i = 4;
vec_push(vec, i);
// vec: 1 2 3 4
```
### vec_safe_at
Gets the stored data at a specified index. Uses safety checks to make sure `index` is not out of bounds. Returns `NULL` if there is an error
```c
void *vec_safe_at(Vector *vec, size_t index);
```
### vec_remove
Removes an element from the array and returns the pointer, then moves elements to shrink the array accordingly. Returns `NULL` if the index is not valid
```c
void *vec_remove(Vector *vec, size_t index);
/* Usage */
// vec: 1 2 3 4
int *t = NULL;
t = (int*)vec_remove(vec, 2);
assert(*t == 3);
// vec: 1 2 4
```
### vec_shrink
Shrinks the capacity of the vector down to the current length. Returns a non-zero integer if there is an error
```c
int vec_shrink(Vector *vec);
```
### vec_max
Finds the largest value in the vector and returns a void pointer to the underlying data. Requires a
comparison function to compare the data in the vector. This function must return `1` if `a > b`, `-1` if
`a < b`, or `0` if `a == b`. See the supplied comparison functions below for reference
```c
const void *vec_min(const Vector *vec, int(*cmp)(const void *a, const void *b));
```
### vec_min
Finds the smallest value in the vector and returns a void pointer to the underlying data. Requires a
comparison function to compare the data in the vector. This function must return `1` if `a > b`, `-1` if
`a < b`, or `0` if `a == b`. See the supplied comparison functions below for reference
```c
const void *vec_max(const Vector *vec, int(*cmp)(const void *a, const void *b));
```
## Macros
### vec_at
Grabs the element at index `i` without safety checks for better performance. Use with caution
```c
#define vec_at(v, i) (v)->elements[(i)]
```
### vec_len
Returns the length of the vector
```c
#define vec_len(v) (v)->length
```
### vec_cap
Returns the capacity of the vector
```c
#define vec_cap(v) (v)->capacity
```

View File

@ -3,15 +3,15 @@
#include <stddef.h>
char *b64_encode(const unsigned char *s, size_t sz);
const char *b64_encode(const unsigned char *s, size_t sz);
unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz);
char *hex_encode(const unsigned char *hex, size_t sz);
const char *hex_encode(const unsigned char *hex, size_t sz);
unsigned char *hex_decode(const char *orig, size_t *sz);
char *hex_to_str(const unsigned char *hex, size_t sz);
const char *hex_to_str(const unsigned char *hex, size_t sz);
unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz);
unsigned char *repeating_key_xor_s(const char* s, const char* key);
const unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz);
const unsigned char *repeating_key_xor_s(const char* s, const char* key);
unsigned int hamming_distance_s(const char *a, const char *b);
unsigned int hamming_distance(unsigned char *a, unsigned char *b, size_t sz);

View File

@ -17,8 +17,4 @@ void del_split(char **);
void del_lines(char **);
#define DEFAULT_CAPTURE_SYSTEM_BUFSIZE 1024
const char *capture_system(const char *cmd, int buf_sz);
#endif // LIBFLINT_INPUT_H

View File

@ -1,8 +1,6 @@
#ifndef LIBFLINT_H_MATH
#define LIBFLINT_H_MATH
#include <stddef.h>
#include "lfutility.h"
int max_int(int a, int b);
@ -13,10 +11,13 @@ int clamp_int(int i, int low, int high);
int binstr_to_int(const char *s);
int is_power_of_two(int i);
Point *bresenham(int x0, int y0, int x1, int y1, size_t *sz);
Point *bresenham_p(Point p1, Point p2, size_t *sz);
int compar_int(const void *a, const void *b);
int compar_char(const void *a, const void *b);
#endif // LIBFLINT_H_MATH

View File

@ -1,42 +0,0 @@
#ifndef LIBFLINT_H_MEMORY
#define LIBFLINT_H_MEMORY
#include <stddef.h>
#include "lflinkedlist.h"
#ifndef DEFAULT_ALIGNMENT
#define LF_DEFAULT_ALIGNMENT (2*sizeof(void*))
#endif // DEFAULT_ALIGNMENT
typedef struct {
unsigned char* buf;
size_t buf_sz;
size_t offset_cur;
size_t offset_prev;
} ArenaAllocator;
void arena_init(ArenaAllocator *allocator, size_t buf_sz);
void arena_free(ArenaAllocator *allocator);
void *arena_malloc(ArenaAllocator* allocator, size_t size);
void arena_resize_buf(ArenaAllocator *allocator, size_t new_sz);
void *arena_resize(ArenaAllocator *allocator, void *mem, size_t old_sz, size_t new_sz);
void arena_clear(ArenaAllocator *allocator);
typedef struct {
unsigned char *buf;
size_t buf_sz;
size_t chunk_size;
List *free_list;
} PoolAllocator;
void pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align);
void pool_free(PoolAllocator *allocator, void *ptr);
void pool_free_all(PoolAllocator *allocator);
void *pool_alloc(PoolAllocator *allocator);
void pool_destroy(PoolAllocator *allocator);
#define pool_count_available(x) (x)->free_list->size
#endif // LIBFLINT_H_MEMORY

View File

@ -1,28 +0,0 @@
#ifndef LIBFLINT_NET_H
#define LIBFLINT_NET_H
#include <netdb.h>
typedef enum ServerType {
SERVERTYPE_TCP,
SERVERTYPE_UDP
} ServerType;
typedef struct Server {
ServerType server_type;
int fd;
int port;
void (*handler)(struct Server *s);
} Server;
#define DEFAULT_BACKLOG 5
Server *new_server(ServerType type, const char *port, void(handler)(Server *s));
void delete_server(Server *s);
int serve(Server *s, int backlog_size);
void *get_in_addr(struct sockaddr *sa);
// Example handlers
void handler_tcp_echo(Server *s);
#endif //LIBFLINT_NET_H

View File

@ -5,6 +5,6 @@
int find_substrings(const char* haystack, const char* needle, size_t *num_substrings, size_t **substrings);
char* substr(const char* str, size_t idx, size_t len);
const char* substr(const char* str, size_t idx, size_t len);
#endif // LIBFLINT_H_STRING

View File

@ -18,7 +18,7 @@ void vec_destroy(Vector *vec);
int vec_insert(Vector *vec, void *data, size_t index);
int vec_push(Vector *vec, void *data, size_t *index);
int vec_push(Vector *vec, void *data);
void *vec_safe_at(Vector *vec, size_t index);
@ -30,9 +30,7 @@ const void *vec_min(const Vector *vec, int(*cmp)(const void *a, const void *b));
const void *vec_max(const Vector *vec, int(*cmp)(const void *a, const void *b));
int vec_cmp_int(const void *a, const void *b);
int vec_cmp_char(const void *a, const void *b);
int vec_sort(Vector *vec, int(*cmp)(const void *a, const void *b));
#define vec_at(v, i) (v)->elements[(i)]

View File

@ -12,8 +12,6 @@ nav:
- 'Linked List': 'linkedlist.md'
- 'Math': 'math.md'
- 'macOS': 'macos.md'
- 'Memory': 'memory.md'
- 'Network': 'network.md'
- 'Parsing': 'parsing.md'
- 'Set': 'set.md'
- 'Stack': 'stack.md'

View File

@ -1,12 +0,0 @@
set -e
#./testrunner
./tcptest &
tcpout=$(echo "hello" | nc localhost 18632)
echo "tcpout: $tcpout"
if [ "$tcpout" != "TEST SEND" ]; then
echo "Error: \"$tcpout\" != \"TEST SEND\""
exit 1
fi
exit 0

View File

@ -146,8 +146,8 @@ void print_node(char *prefix, BinTreeNode *node, int is_left, void (*pfunc)(void
pfunc(node->data);
char new_prefix[64];
memset(new_prefix, 0, 64);
strlcat(new_prefix, prefix, 64);
strlcat(new_prefix, (is_left == 1 ? "" : " "), 64 - strlen(prefix));
strcat(new_prefix, prefix);
strcat(new_prefix, (is_left == 1 ? "" : " "));
print_node(new_prefix, node->left, 1, pfunc);
print_node(new_prefix, node->right, 0, pfunc);
}

View File

@ -20,7 +20,7 @@ static const char b64_table[] = {
typedef struct {
unsigned char *ptr;
size_t count;
int count;
} b64_buf;
static int new_b64_buf(b64_buf *b) {
@ -45,7 +45,7 @@ static int resize_b64_buf(b64_buf *b, size_t sz) {
return 0;
}
char *b64_encode(const unsigned char *s, size_t sz) {
const char *b64_encode(const unsigned char *s, size_t sz) {
int i = 0;
b64_buf encbuf;
size_t size = 0;
@ -204,7 +204,7 @@ unsigned char *b64_decode(const char *s, size_t sz, size_t *decode_sz) {
unsigned char *hex_decode(const char *orig, size_t *sz) {
size_t buf_sz = strlen(orig) + 1;
const char *sptr = orig;
char *sptr = orig;
if (strncmp(orig, "0x", 2) == 0) {
buf_sz -= 2;
sptr += 2;
@ -216,10 +216,10 @@ unsigned char *hex_decode(const char *orig, size_t *sz) {
char *buf = malloc(sizeof(char) * buf_sz);
if (strlen(sptr) % 2 != 0) {
strlcpy(buf + 1, sptr, buf_sz - 1);
strcpy(buf+ 1, sptr);
buf[0] = '0';
} else {
strlcpy(buf, sptr, buf_sz);
strcpy(buf, sptr);
}
buf[buf_sz - 1] = '\0';
@ -236,7 +236,7 @@ unsigned char *hex_decode(const char *orig, size_t *sz) {
return hex;
}
char *hex_encode(const unsigned char *hex, size_t sz) {
const char *hex_encode(const unsigned char *hex, size_t sz) {
size_t ssz = sz * 2 + 1;
char *s = malloc(sizeof(char) * ssz);
char *pos = s;
@ -250,7 +250,7 @@ char *hex_encode(const unsigned char *hex, size_t sz) {
return s;
}
char *hex_to_str(const unsigned char *hex, size_t sz) {
const char *hex_to_str(const unsigned char *hex, size_t sz) {
char *s = malloc(sizeof(char) * (sz + 1));
for (size_t i = 0; i < sz; ++i) {
s[i] = (char)hex[i];
@ -259,7 +259,7 @@ char *hex_to_str(const unsigned char *hex, size_t sz) {
return s;
}
unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz) {
const unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsigned char* key, size_t k_sz) {
unsigned char* r = malloc(sizeof(unsigned char) * s_sz);
for (size_t i = 0, j = 0; i < s_sz; ++i) {
r[i] = s[i] ^ key[j];
@ -268,7 +268,7 @@ unsigned char* repeating_key_xor(const unsigned char* s, size_t s_sz, const unsi
return r;
}
unsigned char *repeating_key_xor_s(const char* s, const char* key) {
const unsigned char *repeating_key_xor_s(const char* s, const char* key) {
return repeating_key_xor((unsigned char*)s, strlen(s), (unsigned char*)key, strlen(key));
}

View File

@ -2,7 +2,6 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#ifdef __linux__
@ -122,18 +121,3 @@ void del_split(char **sp) {
void del_lines(char **lines) {
del_split(lines);
}
const char *capture_system(const char *cmd, int buf_sz) {
if (buf_sz == 0) {
buf_sz = DEFAULT_CAPTURE_SYSTEM_BUFSIZE;
}
char *buf = malloc(buf_sz);
FILE *tmp = popen(cmd, "r");
if (tmp == NULL) {
fprintf(stderr, "libflint: failed to open FILE *tmp in capture_system. Errno: %d\n", errno);
free(buf);
return NULL;
}
fgets(buf, buf_sz, tmp);
return buf;
}

View File

@ -77,6 +77,11 @@ Point *bresenham_p(Point p1, Point p2, size_t *sz) {
return bresenham(p1.x, p1.y, p2.x, p2.y, sz);
}
int is_power_of_two(int i) {
return (i & (i - 1)) == 0;
int compar_int(const void *a, const void *b) {
return (*(int*)a - *(int*)b);
}
int compar_char(const void *a, const void *b) {
return (*(char*)a - *(char*)b);
}

View File

@ -1,180 +0,0 @@
#include <lfmath.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "lfmemory.h"
#define arena_sz(a) (a)->buf_sz
void arena_init(ArenaAllocator *allocator, size_t buf_sz) {
if (allocator == NULL) {
return;
}
allocator->buf = malloc(sizeof(unsigned char) * buf_sz);
allocator->buf_sz = buf_sz;
allocator->offset_cur = 0;
allocator->offset_prev = 0;
}
void arena_free(ArenaAllocator *allocator) {
free(allocator->buf);
free(allocator);
}
void arena_clear(ArenaAllocator *allocator) {
allocator->offset_cur = 0;
allocator->offset_prev = 0;
}
static uintptr_t align_forward_uintptr(const uintptr_t ptr, const uintptr_t align) {
if (!is_power_of_two(align)) {
// TODO: Error
}
uintptr_t p = ptr;
const uintptr_t m = p & (align - 1);
if (m != 0) {
p += align - m;
}
return p;
}
static uintptr_t align_forward_size(const size_t ptr, const size_t align) {
if (!is_power_of_two(align)) {
// TODO: Error
}
uintptr_t p = ptr;
const uintptr_t m = p & (align - 1);
if (m != 0) {
p += align - m;
}
return p;
}
static void *arena_malloc_align(ArenaAllocator *allocator, const size_t size, size_t align) {
uintptr_t cur_ptr = (uintptr_t)allocator->buf + allocator->offset_cur;
// Push forward to align, then change to relative offset
uintptr_t offset = align_forward_uintptr(cur_ptr, align);
offset -= (uintptr_t)allocator->buf;
if (offset + size <= allocator->buf_sz) {
void *ptr = &allocator->buf[offset];
allocator->offset_prev = offset;
allocator->offset_cur = offset + size;
memset(ptr, 0, size);
return ptr;
}
// Arena is full
return NULL;
}
static void *arena_resize_align(ArenaAllocator *allocator, void *mem, const size_t old_sz, const size_t new_sz, size_t align) {
unsigned char *old_mem = mem;
if (!is_power_of_two(align)) {
// TODO: Error handling
}
if (old_mem == NULL || old_sz == 0) {
return arena_malloc_align(allocator, new_sz, align);
}
if (allocator->buf <= (unsigned char*)mem && (unsigned char*)mem < allocator->buf + allocator->buf_sz) {
if (allocator->buf + allocator->offset_prev == old_mem) {
allocator->offset_cur = allocator->offset_prev + new_sz;
if (new_sz > old_sz) {
// Zero out memory
memset(&allocator->buf[allocator->offset_cur], 0, new_sz - old_sz);
}
return old_mem;
}
void *new_mem = arena_malloc_align(allocator, new_sz, align);
size_t copy_size = old_sz < new_sz ? old_sz : new_sz;
memmove(new_mem, old_mem, copy_size);
return new_mem;
}
return NULL;
}
void arena_resize_buf(ArenaAllocator *allocator, const size_t new_sz) {
allocator->buf = realloc(allocator->buf, sizeof(unsigned char) * new_sz);
}
void *arena_malloc(ArenaAllocator *allocator, const size_t size) {
return arena_malloc_align(allocator, size, LF_DEFAULT_ALIGNMENT);
}
void *arena_resize(ArenaAllocator *allocator, void *mem, const size_t old_sz, const size_t new_sz) {
return arena_resize_align(allocator, mem, old_sz, new_sz, LF_DEFAULT_ALIGNMENT);
}
void pool_init(PoolAllocator *allocator, size_t buf_sz, size_t chunk_sz, size_t chunk_align) {
if (allocator == NULL) {
return;
}
allocator->buf = malloc(sizeof(unsigned char) * buf_sz);
uintptr_t istart = (uintptr_t)allocator->buf;
uintptr_t start = align_forward_uintptr(istart, chunk_align);
allocator->buf_sz = buf_sz - (start - istart);
allocator->chunk_size = align_forward_size(chunk_sz, chunk_align);
if (allocator->chunk_size < sizeof(void *) || allocator->buf_sz < allocator->chunk_size) {
//TODO: Handle error better
return;
}
allocator->free_list = malloc(sizeof(List));
ll_init(allocator->free_list, NULL);
pool_free_all(allocator);
}
void pool_free(PoolAllocator *allocator, void *ptr) {
ListNode *node = NULL;
const void *start = allocator->buf;
const void *end = &allocator->buf[allocator->buf_sz];
if (ptr == NULL) {
return;
}
if (!(start <= ptr && ptr < end)) {
// TODO: Handle error better
return;
}
ll_ins_next(allocator->free_list, allocator->free_list->tail, ptr);
}
void pool_free_all(PoolAllocator *allocator) {
size_t chunk_count = allocator->buf_sz / allocator->chunk_size;
for (size_t i = 0; i < chunk_count; ++i) {
ll_ins_next(allocator->free_list, allocator->free_list->head, &allocator->buf[i * allocator->chunk_size]);
}
}
void *pool_alloc(PoolAllocator *allocator) {
ListNode *node = allocator->free_list->head;
if (node == NULL) {
// TODO: Handle error better
return NULL;
}
void *tmp;
ll_remove(allocator->free_list, allocator->free_list->head, &tmp);
return memset(tmp, 0, allocator->chunk_size);
}
void pool_destroy(PoolAllocator *allocator) {
ll_destroy(allocator->free_list);
free(allocator->free_list);
free(allocator->buf);
free(allocator);
}

View File

@ -1,150 +0,0 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include "lfnetwork.h"
static void sighandler(int s) {
int saved_errno = errno;
while (waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
Server *new_server(ServerType type, const char *port, void(handler)(Server *s)) {
Server *s = (Server *)malloc(sizeof(Server));
if (s == NULL) {
return NULL;
}
s->server_type = type;
s->handler = handler;
struct addrinfo *addr = NULL;
if (getaddrinfo(NULL, port, NULL, &addr) != 0) {
free(s);
return NULL;
}
s->port = (int)strtol(port, NULL, 10);
int socktype = 0;
switch (type) {
case SERVERTYPE_TCP:
socktype = SOCK_STREAM;
break;
case SERVERTYPE_UDP:
socktype = SOCK_DGRAM;
break;
}
struct addrinfo *p;
for (p = addr; p != NULL; p = p->ai_next) {
s->fd = socket(AF_INET, socktype, 0);
if (s->fd == -1) {
continue;
}
if (bind(s->fd, p->ai_addr, p->ai_addrlen) != 0) {
close(s->fd);
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "Failed to bind\n");
free(s);
return NULL;
}
freeaddrinfo(addr);
return s;
}
void delete_server(Server *s) {
free(s);
s = NULL;
}
int serve(Server *s, int backlog_size) {
if (backlog_size == 0) {
backlog_size = DEFAULT_BACKLOG;
}
if (listen(s->fd, backlog_size) != 0) {
return 1;
}
// Linux doesn't handle SA_RESTART properly, and I don't know about Windows (nor do I care)
// This is just for macOS and BSDs
#if !defined(__linux__) && !defined(_WIN32)
struct sigaction sa;
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
fprintf(stderr, "Failed to set sigaction\n");
return 1;
}
#endif
s->handler(s);
return 0;
}
static void *tcp_echo_thread(void *vargp) {
while (1) {
char recv_buf[256];
int fd = *(int *) vargp;
int r = (int)recv(fd, recv_buf, 256, 0);
if (r < 1) {
if (r == -1) {
fprintf(stderr, "Failed to recv. Errno: %d\n", errno);
}
close(fd);
break;
}
if (send(fd, recv_buf, strlen(recv_buf), 0) == -1) {
fprintf(stderr, "Failed to send echo. Errno: %d\n", errno);
close(fd);
break;
}
}
}
void handler_tcp_echo(Server *s) {
while (1) {
struct sockaddr_storage client_addr;
socklen_t client_addr_sz = sizeof(client_addr);
int new_fd = accept(s->fd, (struct sockaddr *)&client_addr, &client_addr_sz);
if (new_fd == -1) {
fprintf(stderr, "failed to accept. Errno: %d\n", errno);
continue;
}
pthread_t srv_tid;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&srv_tid, &attr, tcp_echo_thread, &new_fd);
}
}

View File

@ -25,5 +25,4 @@ int simple_english_scoring(const char *s) {
score += ses_score_sw(*c);
}
return score;
}
}

View File

@ -40,7 +40,7 @@ int find_substrings(const char* haystack, const char* needle, size_t *num_substr
return 0;
}
char* substr(const char* str, size_t idx, size_t len) {
const char* substr(const char* str, size_t idx, size_t len) {
size_t sz_str = strlen(str);
if (sz_str < len || idx + len > sz_str) {
return NULL;

View File

@ -35,9 +35,7 @@ int vec_init_with_capacity(Vector *vec, void (*destroy)(void *data), size_t capa
static int vec_grow(Vector *const vec) {
vec->capacity *= 2;
vec->elements = reallocarray(vec->elements, vec->capacity, sizeof(void *));
if (vec->elements == NULL) {
return -1;
}
@ -81,10 +79,7 @@ int vec_insert(Vector *vec, void *data, size_t index) {
return 0;
}
int vec_push(Vector *vec, void *data, size_t *index) {
if (index != NULL) {
*index = vec_len(vec);
}
int vec_push(Vector *vec, void *data) {
return vec_insert(vec, data, vec_len(vec));
}
@ -113,19 +108,11 @@ int vec_shrink(Vector *vec) {
if (vec_len(vec) == vec_cap(vec)) {
return 0;
}
vec->capacity = vec_len(vec);
#if !defined(__OpenBSD__)
vec->elements = reallocf(vec->elements, sizeof(void *) * vec->capacity);
#else
vec->elements = reallocarray(vec->elements, vec->capacity, sizeof(void *));
#endif
if (vec->elements == NULL) {
return -1;
}
return 0;
}
@ -149,28 +136,10 @@ const void *vec_max(const Vector *vec, int(*cmp)(const void *a, const void *b))
return a;
}
int vec_cmp_int(const void *a, const void *b) {
const int x = *(int*)a;
const int y = *(int*)b;
if (x > y) {
return 1;
int vec_sort(Vector *vec, int(*cmp)(const void *a, const void *b)) {
if (vec_len(vec) == 0) {
return 0;
}
if (x < y) {
return -1;
}
return 0;
}
int vec_cmp_char(const void *a, const void *b) {
const char x = *(int*)a;
const char y = *(int*)b;
if (x > y) {
return 1;
}
if (x < y) {
return -1;
}
return 0;
qsort(vec->elements, vec->length, sizeof(void *), cmp);
return 1;
}

View File

@ -1,7 +0,0 @@
#include "lfnetwork.h"
int main(int argc, char **argv) {
Server *server = new_server(SERVERTYPE_TCP, "18632", handler_tcp_echo);
serve(server, DEFAULT_BACKLOG);
delete_server(server);
}

View File

@ -2,12 +2,8 @@
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#include "lflinkedlist.h"
#include "lfnetwork.h"
#include "lfset.h"
#include "lfstack.h"
#include "lfbinarytree.h"
@ -16,8 +12,6 @@
#include "lfstring.h"
#include "lfcrypto.h"
#include "lfparsing.h"
#include "lfinput.h"
#include "lfmemory.h"
#if defined(__APPLE__) || defined(__MACH__)
#include "lfmacos.h"
@ -71,9 +65,9 @@ void test_set() {
int j = 2;
int k = 2;
set_insert(set, &i);
set_insert(set, &j);
set_insert(set, &k);
set_insert(set, (void *) &i);
set_insert(set, (void *) &j);
set_insert(set, (void *) &k);
int i2 = 1;
int j2 = 4;
@ -81,8 +75,8 @@ void test_set() {
Set *set2 = malloc(sizeof(Set));
set_init(set2, int_match, NULL);
set_insert(set2, &i2);
set_insert(set2, &j2);
set_insert(set2, (void *) &i2);
set_insert(set2, (void *) &j2);
printf("Set 1:");
print_ll(set);
@ -203,7 +197,7 @@ void test_math() {
void print_vector(Vector *vec) {
for (size_t i = 0; i < vec->length; ++i) {
int t = *(int *) vec_at(vec, i);
int t = *(int*)vec_at(vec, i);
printf("%d ", t);
}
printf("\n");
@ -220,47 +214,45 @@ void test_vector() {
int e3 = 3;
int e4 = 4;
size_t idx = 0;
vec_push(v, &e0, &idx);
assert(idx == 0);
vec_push(v, &e0);
assert(v->length == 1);
int *t = (int *) vec_at(v, 0);
int *t = (int*)vec_at(v, 0);
assert(*t == 0);
vec_push(v, &e1, NULL);
vec_push(v, &e2, NULL);
vec_push(v, &e1);
vec_push(v, &e2);
assert(v->length == 3);
// test access outside bounds
t = (int *) vec_safe_at(v, 3);
t = (int*)vec_safe_at(v, 3);
assert(t == NULL);
printf("Before insert: ");
print_vector(v);
vec_push(v, &e4, NULL);
vec_push(v, &e4);
vec_insert(v, &e3, 3);
printf("After insert: ");
print_vector(v);
t = (int *) vec_at(v, 3);
t = (int*)vec_at(v, 3);
assert(*t == e3);
t = (int *) vec_at(v, 4);
t = (int*)vec_at(v, 4);
assert(*t == e4);
const int *min = vec_min(v, vec_cmp_int);
const int *max = vec_max(v, vec_cmp_int);
const int *min = vec_min(v, compar_int);
const int *max = vec_max(v, compar_int);
printf("min: %d\n", *min);
printf("max: %d\n", *max);
assert(*min == e0);
assert(*max == e4);
t = (int *) vec_remove(v, 1);
t = (int*)vec_remove(v, 1);
assert(t != NULL);
assert(*t == 1);
printf("After removal: ");
print_vector(v);
t = (int *) vec_remove(v, 10);
t = (int*)vec_remove(v, 10);
assert(t == NULL);
printf("\ncap before shrink: %zu\n", vec_cap(v));
@ -268,18 +260,29 @@ void test_vector() {
assert(vec_len(v) == vec_cap(v));
printf("cap after shrink: %zu\n", vec_cap(v));
int s1 = 10;
int s2 = 2;
int s3 = 1;
vec_push(v, &s1);
vec_push(v, &s2);
vec_push(v, &s3);
printf("Before sort: ");
print_vector(v);
vec_sort(v, compar_int);
printf("After sort: ");
print_vector(v);
vec_destroy(v);
free(v);
}
void test_string() {
printf("\n--- STRING TEST ---\n");
const char *haystack =
"Test one two one and also maybe two but not Gabe's least favorite number, which is not one.";
const char *needles[] = {
"one",
"two",
"Gabe"
const char* haystack = "Test one two one and also maybe two but not Gabe's least favorite number, which is not one.";
const char* needles[] = {
"one",
"two",
"Gabe"
};
size_t sub_sz = 0;
@ -291,7 +294,7 @@ void test_string() {
assert(subs[1] == 13);
assert(subs[2] == 87);
char *s = substr(haystack, subs[0], strlen(needles[0]));
const char *s = substr(haystack, subs[0], strlen(needles[0]));
assert(strcmp(s, needles[0]) == 0);
free(s);
@ -335,14 +338,14 @@ void test_crypto() {
char *out2 = "YSBsb25nZXIgYmFzZTY0IHRlc3QsIGFwcGFyZW50bHk=";
size_t s_sz = 0;
s = (char *) b64_decode(out2, strlen(out2), &s_sz);
s = (char *)b64_decode(out2, strlen(out2), &s_sz);
assert(strcmp(s, "a longer base64 test, apparently") == 0);
assert(strlen(s) == s_sz);
free(s);
s = hex_decode("DEADBEEF", &s_sz);
unsigned char h[4] = {
0xDE, 0xAD, 0xBE, 0xEF
0xDE, 0xAD, 0xBE, 0xEF
};
for (size_t i = 0; i < 4; ++i) {
assert(s[i] == h[i]);
@ -352,7 +355,7 @@ void test_crypto() {
// Odd number of characters
s = hex_decode("f00f5", &s_sz);
unsigned char h2[4] = {
0x0F, 0x00, 0xF5
0x0F, 0x00, 0xF5
};
for (size_t i = 0; i < 3; ++i) {
assert(s[i] == h2[i]);
@ -372,20 +375,20 @@ void test_crypto() {
// "Sup?"
unsigned char hexsup[4] = {
0x53, 0x75, 0x70, 0x3F
0x53, 0x75, 0x70, 0x3F
};
s = hex_to_str(hexsup, 4);
assert(strcmp(s, "Sup?") == 0);
free(s);
s = repeating_key_xor_s("TEST", "HI");
char *enc = hex_encode(s, 4);
const char *enc = hex_encode(s, 4);
assert(strcmp(enc, "1c0c1b1d") == 0);
free(enc);
free(s);
unsigned char ua[2] = {0x2, 0xF};
unsigned char ub[2] = {0x4, 0xE};
unsigned char ua[2] = { 0x2, 0xF };
unsigned char ub[2] = { 0x4, 0xE };
unsigned int hamming = hamming_distance(ua, ub, 2);
assert(hamming == 3);
@ -405,60 +408,6 @@ void test_parsing() {
printf("Passes all parsing tests\n");
}
#define NET_MSG "TEST SEND"
void tcp_test_handler(Server *s) {
struct sockaddr_storage client_addr;
socklen_t client_addr_sz = sizeof(client_addr);
int new_fd = accept(s->fd, (struct sockaddr *) &client_addr, &client_addr_sz);
assert(new_fd != -1);
assert(send(new_fd, NET_MSG, 10, 0) != -1);
close(new_fd);
}
void *tcp_server_thread(void *vargp) {
Server *server = new_server(SERVERTYPE_TCP, "18632", tcp_test_handler);
serve(server, DEFAULT_BACKLOG);
delete_server(server);
}
void udp_test_handler(Server *s) {
struct sockaddr_storage client_addr;
socklen_t client_addr_sz = sizeof(client_addr);
char recv_buf[128];
int r = (int) recvfrom(s->fd, recv_buf, 128, 0, (struct sockaddr *) &client_addr, &client_addr_sz);
assert(r > 0);
assert(strcmp(recv_buf, NET_MSG) == 0);
}
void *udp_server_thread(void *vargp) {
Server *server = new_server(SERVERTYPE_UDP, "18633", udp_test_handler);
serve(server, DEFAULT_BACKLOG);
delete_server(server);
}
void test_network() {
printf("\n--- NETWORK TEST ---\n");
pthread_t srv_tid;
pthread_create(&srv_tid, NULL, tcp_server_thread, NULL);
sleep(1);
const char *s = capture_system("echo hello | nc localhost 18632", 0);
assert(strcmp(s, NET_MSG) == 0);
free((char *) s);
pthread_join(srv_tid, NULL);
printf("Passed TCP test\n");
pthread_create(&srv_tid, NULL, udp_server_thread, NULL);
sleep(1);
system("echo hello | nc localhost 18633");
pthread_join(srv_tid, NULL);
printf("Passed UDP test\n");
}
#if defined(__APPLE__) || defined(__MACH__)
void test_macos() {
printf("\n--- macOS TEST ---\n");
@ -474,50 +423,6 @@ void test_macos() {
}
#endif
void test_memory() {
printf("\n--- MEMORY TEST ---\n");
ArenaAllocator *arena = malloc(sizeof(ArenaAllocator));
arena_init(arena, 1024);
int *i1 = arena_malloc(arena, sizeof(int));
int *i2 = arena_malloc(arena, sizeof(int));
*i1 = 1;
*i2 = 2;
assert(i1 < i2);
assert(*i1 < *i2);
long *l = arena_resize(arena, i1, sizeof(int), sizeof(long));
assert(*l == 1);
unsigned char *char_test = arena_resize(arena, i2, sizeof(int), sizeof(unsigned char));
assert(*char_test == 2);
arena_free(arena);
arena = NULL;
PoolAllocator *pool = malloc(sizeof(PoolAllocator));
pool_init(pool, 64, 16, LF_DEFAULT_ALIGNMENT);
void *a = pool_alloc(pool);
void *b = pool_alloc(pool);
void *c = pool_alloc(pool);
void *d = pool_alloc(pool);
assert(a != NULL);
assert(b != NULL);
assert(c != NULL);
assert(d != NULL);
assert(pool_count_available(pool) == 0);
pool_free(pool, d);
d = NULL;
assert(pool_count_available(pool) == 1);
pool_destroy(pool);
printf("Passes all memory tests\n");
}
int main() {
test_ll();
test_set();
@ -528,12 +433,10 @@ int main() {
test_string();
test_crypto();
test_parsing();
test_network();
test_memory();
#if defined(__APPLE__) || defined(__MACH__)
test_macos();
#endif
return 0;
}
}