From ef8470b861a0b4ea52f549a432cc4c41e6646b46 Mon Sep 17 00:00:00 2001 From: MrBesen Date: Mon, 28 Sep 2020 23:49:14 +0200 Subject: [PATCH] initial --- .gitignore | 15 ++++++ .vscode/c_cpp_properties.json | 16 ++++++ .vscode/launch.json | 29 +++++++++++ .vscode/tasks.json | 31 ++++++++++++ Makefile | 69 +++++++++++++++++++++++++ inc/files.h | 11 ++++ inc/mrbesen.h | 4 ++ inc/util.h | 11 ++++ src/Files.cpp | 38 ++++++++++++++ src/Util.cpp | 33 ++++++++++++ tests/filestests.cpp | 95 +++++++++++++++++++++++++++++++++++ tests/main.cpp | 32 ++++++++++++ tests/test.h | 11 ++++ tests/utilstest.cpp | 40 +++++++++++++++ 14 files changed, 435 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json create mode 100644 Makefile create mode 100644 inc/files.h create mode 100644 inc/mrbesen.h create mode 100644 inc/util.h create mode 100644 src/Files.cpp create mode 100644 src/Util.cpp create mode 100644 tests/filestests.cpp create mode 100644 tests/main.cpp create mode 100644 tests/test.h create mode 100644 tests/utilstest.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a0b4bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.bin +*.out +build/ +*.exe +*.o +.gdb_history + +*.so +*.d + +deps/ + +test + +.vscode/settings.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..fd1f3e8 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,16 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/inc/**" + ], + "defines": [], + "compilerPath": "/usr/bin/g++", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..82aa769 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,29 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "test Debuggen (gdb)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/test", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "make test", + "miDebuggerPath": "/usr/bin/gdb" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..c899ce9 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "make all", + "type": "shell", + "command": "make -j all", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "make clean", + "type": "shell", + "command": "make clean", + "problemMatcher": [] + }, + { + "label": "make test", + "type": "shell", + "command": "make -j test", + "problemMatcher": ["$gcc"], + } + ] +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5a125de --- /dev/null +++ b/Makefile @@ -0,0 +1,69 @@ +# Author Yannis Gerlach +# Hochschule Osnabrück +# 28.09.2020 + +# `make clean all` nicht mit -j verwenden! -> race condition im make file +# statdessen: `make clean; make all -j` verwenden + +NAME = libmrbesen.so +NAMEINC = mrbesen +NAMETEST = test +CFLAGS = -fpic -std=c++17 -O2 -g -pipe -Wall -Wextra -Wno-unused-parameter -Wpedantic +CXX = g++ +SRCF = src/ +BUILDDIR = build/ +INCF = inc/ +TESTF = tests/ +DEPF = $(BUILDDIR)deps/ + +INCLUDES = -I$(INCF) +LDFLAGS = + +SRCFILES = $(shell find $(SRCF) -name "*.cpp") +OBJFILES = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(patsubst %.cpp, %.o, $(SRCFILES))) +DEPFILES = $(wildcard $(DEPF)*.d) + +SOURCEDIRS = $(shell find $(SRCF) -type d -printf "%p/\n") +BUILDDIRS = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(SOURCEDIRS)) + +INCLUDES += $(addprefix -I, $(SOURCEDIRS)) + +all: $(NAME) runtest + +$(NAME): $(BUILDDIRS) $(DEPF) $(OBJFILES) + @echo "Linking $@" + @$(LD) -shared -o $@ $(filter %.o, $^) + +$(BUILDDIR)%.o: $(SRCF)%.cpp + @echo "Compiling: $@" + @$(CXX) $(CFLAGS) $(INCLUDES) $< -MM -MT $@ > $(DEPF)$(subst /,_,$*).d + @$(CXX) -c -o $@ $(CFLAGS) $(INCLUDES) $< + +%/: + mkdir -p $@ + +clean-depends: + $(RM) -r $(DEPF) + +clean: + $(RM) -r $(NAME) $(BUILDDIR) $(NAMETEST) + +$(NAMETEST): $(NAME) $(TESTF)*.cpp + @echo "Compiling tests" + @$(CXX) -o $@ $(filter-out %.so, $^) $(CFLAGS) $(INCLUDES) $(LDFLAGS) -L./ -lmrbesen + +runtest: $(NAMETEST) + @echo "Running tests" + LD_LIBRARY_PATH=./:$(LD_LIBRARY_PATH) ./$< + +install: $(NAME) + cp -f ./$(NAME) /usr/lib/ + mkdir -p /usr/include/$(NAMEINC)/ + cp -rf $(INCF)* /usr/include/$(NAMEINC)/ + +uninstall: + $(RM) -r /usr/lib/$(NAME) /usr/include/$(NAMEINC)/ + +.PHONY: clean all $(NAMETEST) clean-depends runtest install + +include $(DEPFILES) diff --git a/inc/files.h b/inc/files.h new file mode 100644 index 0000000..943a75a --- /dev/null +++ b/inc/files.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace mrbesen::Files { + +void parent(const std::string& child, std::string& out); //get the parent directory of a file or directory path +void file(const std::string& path, std::string& out); //get the filename without the path +void extention(const std::string& path, std::string& ext); //get the files extenetion + +} \ No newline at end of file diff --git a/inc/mrbesen.h b/inc/mrbesen.h new file mode 100644 index 0000000..d0db718 --- /dev/null +++ b/inc/mrbesen.h @@ -0,0 +1,4 @@ +#include "files.h" +#include "util.h" + +#define LIBMRBESEN_VERSION "0.0.1" diff --git a/inc/util.h b/inc/util.h new file mode 100644 index 0000000..5c29b88 --- /dev/null +++ b/inc/util.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace mrbesen::Util { + +unsigned int count(const std::string& str, char c); //count occurances of c in str + +bool equalsIgnoreCase(const std::string& a, const std::string& b, size_t max = std::string::npos); + +} \ No newline at end of file diff --git a/src/Files.cpp b/src/Files.cpp new file mode 100644 index 0000000..3309599 --- /dev/null +++ b/src/Files.cpp @@ -0,0 +1,38 @@ +#include "files.h" + +void mrbesen::Files::parent(const std::string& child, std::string& out) { + //letzten path trenner finden + size_t pos = child.rfind('/', child.length() -2); //das erste Zeichen überspringen (könnte ein / sein) + if(pos == std::string::npos) + pos = child.rfind('\\'); + if(pos != std::string::npos) + out = child.substr(0, pos+1); + else + out = ""; +} + +void mrbesen::Files::file(const std::string& path, std::string& out) { + //letzten path trenner finden + size_t pos = path.rfind('/', path.length() -2); //das erste Zeichen überspringen (könnte ein / sein) + if(pos == std::string::npos) + pos = path.rfind('\\'); + if(pos != std::string::npos) + out = path.substr(pos+1); + else + out = path; +} + +void mrbesen::Files::extention(const std::string& path, std::string& ext) { + size_t pos = path.rfind('.'); + if(pos == std::string::npos || pos+1 == path.size()) { + ext = ""; + return; + } + ext = path.substr(pos+1); + + //TODO: + //was ist mit dotfiles?? -> prüfen auf '/' for '.'? oder auf string position (damit der punkt icht ganz links sei kann)? + + //problem: "a.b/file" würde .b/file zurückgeben -> muss also auch auf '/' geprüft werden! +} + diff --git a/src/Util.cpp b/src/Util.cpp new file mode 100644 index 0000000..9ce7598 --- /dev/null +++ b/src/Util.cpp @@ -0,0 +1,33 @@ +#include "util.h" + +unsigned int mrbesen::Util::count(const std::string& str, char c) { + size_t pos = 0; + long count = -1; + do { + pos = str.find(c, pos); + ++count; + } while((pos++) != std::string::npos); + return (unsigned int) count; +} + +bool icompare_pred(unsigned char a, unsigned char b) { + return std::tolower(a) == std::tolower(b); +} + +bool mrbesen::Util::equalsIgnoreCase(const std::string& a, const std::string& b, size_t max) { + size_t al = a.size(), bl = b.size(); + if((al == 0 && bl == 0) || max == 0) return true; + + if(al != bl && (al < max || bl < max)) { + return false; + } + + if(max == std::string::npos) { + return std::equal(b.begin(), b.end(), a.begin(), icompare_pred); + } else { + if(max > al) max = al; + if(max > bl) max = bl; + + return std::equal(b.begin(), b.begin()+max, a.begin(), icompare_pred); + } +} diff --git a/tests/filestests.cpp b/tests/filestests.cpp new file mode 100644 index 0000000..9ebf496 --- /dev/null +++ b/tests/filestests.cpp @@ -0,0 +1,95 @@ +#include "test.h" +#include "files.h" + +#include + +using namespace mrbesen; + +int testFiles_parent() { + std::string out, out2; + std::string testpath1 = "/asdf1/asdf2/test.png"; + + Files::parent(testpath1, out); + ASSERT(out == "/asdf1/asdf2/", out); + + Files::parent(out, out2); + ASSERT(out2 == "/asdf1/", out2); + + Files::parent(out2, out); + ASSERT(out == "/", out); + + testpath1 = "assets/tex/img1.png"; + Files::parent(testpath1, out); + ASSERT(out == "assets/tex/", out); + + Files::parent("asd", out); + ASSERT(out == "", out); + + return TESTGOOD; +} + +int testFiles_file() { + std::string a; + + Files::file("/abc/def/123.txt", a); + ASSERT(a == "123.txt", "normalfile" << a); + + Files::file("/abc/def/.gitignore", a); + ASSERT(a == ".gitignore", "dotfiles" << a); + + Files::file("/abc/def/executeable", a); + ASSERT(a == "executeable", "no extention" << a); + + Files::file("123.txt", a); + ASSERT(a == "123.txt", "normalfile - nopath" << a); + + Files::file(".gitignore", a); + ASSERT(a == ".gitignore", "dotfiles - nopath " << a); + + Files::file("executeable", a); + ASSERT(a == "executeable", "no extention - nopath " << a); + + return TESTGOOD; +} + +int testFiles_extention() { + std::string a; + + Files::extention("abc/asd/1.txt", a); + ASSERT(a == "txt", a); + + Files::extention("1.txt", a); + ASSERT(a == "txt", a); + + Files::extention("/1.txt", a); + ASSERT(a == "txt", ""); + + Files::extention("/a.b.c/ad./1.txt", a); + ASSERT(a == "txt", ""); + + Files::extention("a.b.c/ad./1.txt", a); + ASSERT(a == "txt", ""); + + Files::extention("./1.txt", a); + ASSERT(a == "txt", ""); + + Files::extention("/a/ad/1", a); + ASSERT(a == "", ""); + + Files::extention("/a/ad/", a); + ASSERT(a == "", ""); + + Files::extention("/", a); + ASSERT(a == "", ""); + + Files::extention("/a", a); + ASSERT(a == "", ""); + + Files::extention("/a.", a); + ASSERT(a == "", ""); + + Files::extention("/a.b", a); + ASSERT(a == "b", ""); + + return TESTGOOD; +} diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..71e7484 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,32 @@ +#include +#include "test.h" + +//tests +int testFiles_parent(); +int testFiles_file(); +int testFiles_extention(); + +int testUtil_Count(); +int testUtil_equalsIgnoreCase(); + +test_t tests[] = {testFiles_parent, testFiles_file, testFiles_extention, testUtil_Count, testUtil_equalsIgnoreCase, NULL}; + +int main(int argc, char** argv) { + + test_t* current = tests; + int failcount = 0; + int testcount = 0; + for(; *current; current++) { + testcount++; + printf("\033[1mRunning test number: %d ", testcount); + if((*current)()) { + printf("\033[1;92msucceeded\033[0;1m!\n"); + } else { + printf("\033[1;91mfailed\033[0;1m\n"); + failcount++; + } + } + + printf("\033[1;93m%d\033[0;1m/%d failed\n", failcount, testcount); + return failcount > 0; +} diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..890d25b --- /dev/null +++ b/tests/test.h @@ -0,0 +1,11 @@ +#define TESTFAILED 0 +#define TESTGOOD 1 + +#include + +#define TESTDATA "./tests/data/" + +#define ASSERT(BED, ERR) if(!(BED)) { std::cout << __FILE__ << ":" << __LINE__ << " " << ERR << std::endl; return TESTFAILED; } +// #define ASSERT(BED) ASSERT(BED, "") + +typedef int (*test_t)(); diff --git a/tests/utilstest.cpp b/tests/utilstest.cpp new file mode 100644 index 0000000..d4f341d --- /dev/null +++ b/tests/utilstest.cpp @@ -0,0 +1,40 @@ +#include "util.h" +#include "test.h" + +using namespace mrbesen::Util; + +int testUtil_Count() { + std::string test1 = "ababababa"; + std::string a; + + ASSERT(count(test1, 'a') == 5, ""); + + ASSERT(count(test1, 'b') == 4, ""); + + ASSERT(count("", 'a') == 0, ""); + + ASSERT(count("abcdef", 'g') == 0, ""); + + return TESTGOOD; +} + +int testUtil_equalsIgnoreCase() { + + std::string a = "abcdefg"; + std::string b = "AbCdEHI"; + std::string c = "AbCdEHIJ"; + + ASSERT(!equalsIgnoreCase(a, b), ""); + ASSERT(!equalsIgnoreCase(a, b, 10000), ""); + ASSERT(equalsIgnoreCase(a, b, 0), ""); + + ASSERT(equalsIgnoreCase(a, b, 5), ""); + ASSERT(!equalsIgnoreCase(a, b, 6), ""); + ASSERT(!equalsIgnoreCase(a, b, 7), ""); + ASSERT(!equalsIgnoreCase(a, b, 8), ""); //eins länger als die strings sind + + ASSERT(!equalsIgnoreCase(a, c, 8), ""); + ASSERT(equalsIgnoreCase(a, c, 5), ""); + + return TESTGOOD; +} \ No newline at end of file