Compare commits
1 Commits
master
...
vector_sor
Author | SHA1 | Date | |
---|---|---|---|
04e4d07e99 |
63
.gitea/workflows/jobs.yaml
Normal file
63
.gitea/workflows/jobs.yaml
Normal 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
3
.gitignore
vendored
@ -5,7 +5,4 @@ compile_commands.json
|
||||
site
|
||||
libflint.so
|
||||
test
|
||||
tcptest
|
||||
testrunner
|
||||
.idea
|
||||
netmanual
|
||||
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
flint
|
91
.idea/editor.xml
generated
Normal file
91
.idea/editor.xml
generated
Normal 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
2
.idea/libfputs.iml
generated
Normal 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
7
.idea/misc.xml
generated
Normal 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
8
.idea/modules.xml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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>
|
@ -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()
|
||||
|
37
Makefile
37
Makefile
@ -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
|
||||
|
18
README.md
18
README.md
@ -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
10
build.sh
Executable 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
|
17
clanggen.sh
17
clanggen.sh
@ -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
203
docs/binarytree.md
Normal 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
8
docs/bool.md
Normal file
@ -0,0 +1,8 @@
|
||||
# bool
|
||||
|
||||
Macro representation of truthy values
|
||||
|
||||
```c
|
||||
#define LFTRUE 1
|
||||
#define LFFALSE 0
|
||||
```
|
107
docs/crypto.md
Normal file
107
docs/crypto.md
Normal 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
BIN
docs/flinty.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
25
docs/index.md
Normal file
25
docs/index.md
Normal 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.
|
||||
|
||||

|
103
docs/input.md
Normal file
103
docs/input.md
Normal 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
230
docs/linkedlist.md
Normal 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
72
docs/macos.md
Normal 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
74
docs/math.md
Normal 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
14
docs/parsing.md
Normal 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
3
docs/set.md
Normal file
@ -0,0 +1,3 @@
|
||||
# set
|
||||
|
||||
Coming soon
|
74
docs/stack.md
Normal file
74
docs/stack.md
Normal 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
46
docs/string.md
Normal 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
16
docs/utility.md
Normal 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
164
docs/vector.md
Normal 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
|
||||
```
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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'
|
||||
|
12
run_tests.sh
12
run_tests.sh
@ -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
|
@ -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);
|
||||
}
|
||||
|
18
src/crypto.c
18
src/crypto.c
@ -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));
|
||||
}
|
||||
|
||||
|
16
src/input.c
16
src/input.c
@ -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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
180
src/memory.c
180
src/memory.c
@ -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);
|
||||
}
|
150
src/network.c
150
src/network.c
@ -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);
|
||||
}
|
||||
}
|
@ -25,5 +25,4 @@ int simple_english_scoring(const char *s) {
|
||||
score += ses_score_sw(*c);
|
||||
}
|
||||
return score;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
|
43
src/vector.c
43
src/vector.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
187
tests/tests.c
187
tests/tests.c
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user