From 4f3760fc3b647fa166da4ab777eb612b14ac500b Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Wed, 15 Jul 2026 21:05:19 +0200 Subject: Umbau auf modernes C++ --- .clang-format | 46 ++++++++++++++++++++++++++++ .clang-tidy | 21 +++++++++++++ .gitignore | 2 ++ bin/.gitkeep | 0 compile_flags.txt | 8 +++++ config.mk | 2 ++ include/xml.hpp | 45 +++++++++++++++------------ makefile | 50 +++++++----------------------- obj/.gitkeep | 0 src/xml.cpp | 50 ++++++++++++++++-------------- src/xml_test.cpp | 92 ++++++++++++++++++++++++++++++++++++------------------- 11 files changed, 203 insertions(+), 113 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitignore delete mode 100644 bin/.gitkeep create mode 100644 compile_flags.txt create mode 100644 config.mk delete mode 100644 obj/.gitkeep diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..67bca59 --- /dev/null +++ b/.clang-format @@ -0,0 +1,46 @@ +--- +AccessModifierOffset: -4 +AlignConsecutiveAssignments: 'true' +AlignConsecutiveDeclarations: 'true' +AlignEscapedNewlines: Left +AlignTrailingComments: 'true' +AlwaysBreakAfterReturnType: TopLevelDefinitions +BreakBeforeBraces: Stroustrup +BreakConstructorInitializers: BeforeComma +BreakInheritanceList: BeforeComma +ColumnLimit: '0' +CompactNamespaces: 'false' +Cpp11BracedListStyle: 'false' +FixNamespaceComments: 'true' +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^.*(precomp|pch|stdafx)' + Priority: -1 + - Regex: '^<.*>' + Priority: 1 + - Regex: '^".*"' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: 'false' +IndentPPDirectives: AfterHash +IndentWidth: '4' +IndentWrappedFunctionNames: 'false' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +PointerAlignment: Left +SortIncludes: 'true' +SpaceAfterCStyleCast: 'true' +SpaceAfterTemplateKeyword: 'false' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'false' +SpaceInEmptyParentheses: 'false' +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInConditionalStatement: 'true' +SpacesInParentheses: 'false' +Standard: Auto +TabWidth: '4' +UseTab: ForIndentation +... + diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..635ef64 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,21 @@ +--- +Checks: "*, + -abseil-*, + -altera-*, + -android-*, + -fuchsia-*, + -google-*, + -llvm*, + -modernize-use-trailing-return-type, + -zircon-*, + -readability-else-after-return, + -readability-static-accessed-through-instance, + -readability-avoid-const-params-in-decls, + -cppcoreguidelines-non-private-member-variables-in-classes, + -misc-non-private-member-variables-in-classes, + -cppcoreguidelines-pro-type-reinterpret-cast, + -cppcoreguidelines-pro-bounds-pointer-arithmetic +" +WarningsAsErrors: '' +HeaderFilterRegex: '' +FormatStyle: none diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1746e32 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin +obj diff --git a/bin/.gitkeep b/bin/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/compile_flags.txt b/compile_flags.txt new file mode 100644 index 0000000..86c17bb --- /dev/null +++ b/compile_flags.txt @@ -0,0 +1,8 @@ +-Wall +-Werror +-Wextra +-Wconversion +-Wdouble-promotion +-pedantic +-std=c++20 +-Iinclude diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..209f15c --- /dev/null +++ b/config.mk @@ -0,0 +1,2 @@ +CXXFLAGS=-Wall -Werror -Wextra -Wconversion -Wdouble-promotion -pedantic -std=c++20 -Iinclude +LDFLAGS=-lexpat diff --git a/include/xml.hpp b/include/xml.hpp index cc593a3..bc1fe47 100644 --- a/include/xml.hpp +++ b/include/xml.hpp @@ -1,28 +1,33 @@ -#ifndef XML_HPP_INCLUDED -#define XML_HPP_INCLUDED +#pragma once // Standard C++ -#include -#include +#include +#include +#include #include class XML { - public: - void parse(std::istream& in); +public: + XML() = default; + virtual ~XML() = default; + XML(const XML&) = default; + XML(XML&&) = default; + XML& operator=(const XML&) = default; + XML& operator=(XML&&) = default; - protected: - virtual void handle_start(const std::string& name, const std::vector>& attr) = 0; - virtual void handle_end(const std::string& name) = 0; - virtual void handle_cdata_start() {} - virtual void handle_cdata_end() {} - virtual void handle_data(const std::vector&) {} + void parse(std::istream& ins); - private: - static void tag_start(void* me, const char* name, const char* attr[]); - static void tag_end(void* me, const char* name); - static void cdata_start(void* me); - static void cdata_end(void* me); - static void data(void* me, const char* dat, int len); -}; +protected: + virtual void handle_start(std::string_view name, const std::vector>& attr) = 0; + virtual void handle_end(std::string_view name) = 0; + virtual void handle_cdata_start() {} + virtual void handle_cdata_end() {} + virtual void handle_character_data(std::span /* data */) {} -#endif +private: + static void tag_start(void* self, const char* name, const char** attr); + static void tag_end(void* self, const char* name); + static void cdata_start(void* self); + static void cdata_end(void* self); + static void data(void* self, const char* dat, int len); +}; diff --git a/makefile b/makefile index 637130c..12b6ad2 100644 --- a/makefile +++ b/makefile @@ -1,47 +1,19 @@ -EXE = bin/xml.exe +include config.mk -all: $(EXE) +all: bin/xml_test -EMPTY = +OBJS = obj/xml.obj obj/xml_test.obj -CONTRIB = ../contrib +bin/xml_test: $(OBJS) | bin + c++ $(LDFLAGS) -o $@ $(OBJS) -EXPAT_DIR = $(CONTRIB)/expat-2.2.0 -EXPAT_INCLUDE_DIR = $(EXPAT_DIR)/lib -EXPAT_LIB_DIR = $(EXPAT_DIR)/win32/bin/Release -EXPAT_LIBS = libexpatMT.lib +obj/%.obj: src/%.cpp | obj + c++ $(CXXFLAGS) -c $< -o $@ -OBJS = \ - obj/xml.obj \ - obj/xml_test.obj \ - $(EMPTY) - -WIN32_LIBS = kernel32.lib comdlg32.lib user32.lib gdi32.lib ole32.lib wsock32.lib Ws2_32.lib comctl32.lib shell32.lib oleaut32.lib advapi32.lib uuid.lib Winspool.lib - -# === Compilereinstellungen === - -CPPFLAGS=-nologo -EHsc -Ox -MT -W4 -WX -Iinclude -I$(EXPAT_INCLUDE_DIR) -DWIN32 -D_WINDOWS -D_CRT_NOFORCE_MANIFEST -D_CRT_SECURE_NO_WARNINGS -DNDEBUG - -# === Linkereinstellungen === - -LDFLAGS=-nologo -MANIFEST:NO -LIBPATH:$(EXPAT_LIB_DIR) -LDFLAGS2=$(WIN32_LIBS) $(EXPAT_LIBS) - -$(EXE): $(OBJS) - @echo link $@ - @link.exe $(LDFLAGS) -out:$@ $(LDFLAGS2) $(OBJS) - -obj/%.obj: src/%.cpp - @echo compiling $@ - cl $(CPPFLAGS) -Tp$< -c -Fo$@ - -obj/%.obj: src/%.c - @echo compiling $@ - @cl $(CPPFLAGS) -Tc$< -c -Fo$@ +bin obj: + mkdir -p $@ clean: - @echo cleaning... - @del bin\*.exe - @del obj\** - @del *.pdb + rm -rf bin obj +.PHONY: all clean diff --git a/obj/.gitkeep b/obj/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/xml.cpp b/src/xml.cpp index 44b423a..451ee18 100644 --- a/src/xml.cpp +++ b/src/xml.cpp @@ -1,18 +1,19 @@ // Standard C++ +#include #include #include +#include -// Projekt +// Project #include "xml.hpp" // Expat XML Parser -#define XML_STATIC // force static linkage #include "expat.h" using namespace std; void -XML::parse(istream& in) +XML::parse(istream& ins) { unique_ptr parser(XML_ParserCreate(nullptr), XML_ParserFree); @@ -22,54 +23,57 @@ XML::parse(istream& in) XML_SetCdataSectionHandler(parser.get(), cdata_start, cdata_end); XML_SetCharacterDataHandler(parser.get(), data); - char buffer[2048]; - for ( bool done = false; !done ; ) { - in.read(buffer, sizeof buffer); - done = (in.gcount() < sizeof buffer); + static const auto buffer_size = 2048; - if ( XML_Parse(parser.get(), buffer, static_cast(in.gcount()), done) != XML_STATUS_OK ) { + array buffer{}; + + for ( bool done = false; !done; ) { + ins.read(buffer.data(), buffer_size); + done = ins.gcount() < buffer_size; + + if ( XML_Parse(parser.get(), buffer.data(), static_cast(ins.gcount()), static_cast(done)) != XML_STATUS_OK ) { stringstream msg; msg << XML_ErrorString(XML_GetErrorCode(parser.get())); msg << " in line " << XML_GetCurrentLineNumber(parser.get()); - throw runtime_error( msg.str() ); + throw runtime_error(msg.str()); } } } void -XML::tag_start(void* me, const char* name, const char* attr[]) +XML::tag_start(void* self, const char* name, const char** attr) { - vector> attr_temp; + vector> attr_temp; - for ( size_t i = 0; attr[i]; i += 2 ) - attr_temp.push_back( make_pair(attr[i], attr[i+1]) ); + for ( auto i = 0; attr[i] != nullptr; i += 2 ) { + attr_temp.emplace_back(attr[i], attr[i + 1]); + } - reinterpret_cast(me)->handle_start(name, attr_temp); + static_cast(self)->handle_start(name, attr_temp); } void -XML::tag_end(void* me, const char* name) +XML::tag_end(void* self, const char* name) { - reinterpret_cast(me)->handle_end(name); + static_cast(self)->handle_end(name); } void -XML::cdata_start(void* me) +XML::cdata_start(void* self) { - reinterpret_cast(me)->handle_cdata_start(); + static_cast(self)->handle_cdata_start(); } void -XML::cdata_end(void* me) +XML::cdata_end(void* self) { - reinterpret_cast(me)->handle_cdata_end(); + static_cast(self)->handle_cdata_end(); } void -XML::data(void* me, const char* dat, int len) +XML::data(void* self, const char* dat, int len) { - reinterpret_cast(me)->handle_data(vector(dat, dat+len)); + static_cast(self)->handle_character_data({ dat, dat + len }); } - diff --git a/src/xml_test.cpp b/src/xml_test.cpp index 0af5b51..0b978a9 100644 --- a/src/xml_test.cpp +++ b/src/xml_test.cpp @@ -1,48 +1,78 @@ #include #include +#include using namespace std; #include "xml.hpp" class MyXML : public XML { - public: - explicit MyXML(ostream& out, size_t indent = 4) - : pout_(&out) - , depth_(0) - , indent_(indent) - { - } +public: + explicit MyXML(ostream& out, size_t indent = 4) + : pout_(&out) + , indent_(indent) + { + } - protected: - void handle_start(const string& name, const vector>& attr) - { - *pout_ << string(depth_++ * indent_, ' ') - << "<" << name; +protected: + void handle_start(string_view name, const vector>& attr) override + { + *pout_ << string(depth_++ * indent_, ' ') + << "<" << name; - auto it = cbegin(attr); - auto end = cend(attr); - if ( it != end ) { - *pout_ << " " << it->first << "=\"" << it->second << "\""; + auto start = cbegin(attr); + auto end = cend(attr); + if ( start != end ) { + *pout_ << " " << get<0>(*start) << "=\"" << get<1>(*start) << "\""; - ++it; // skip first Element - for ( ; it != end; ++it ) - *pout_ << ", " << it->first << "=\"" << it->second << "\""; + ++start; // skip first Element + for ( ; start != end; ++start ) { + *pout_ << ", " << get<0>(*start) << "=\"" << get<1>(*start) << "\""; } - - *pout_ << ">" << endl; } - void handle_end(const string& name) - { - *pout_ << string(--depth_ * indent_, ' ') - << "" - << endl; + *pout_ << ">" << '\n'; + } + + void handle_end(string_view name) override + { + *pout_ << string(--depth_ * indent_, ' ') + << "" + << '\n'; + } + void handle_cdata_start() override + { + *pout_ << string(depth_ * indent_, ' ') + << "" << '\n'; + } + + static bool contains_only_whitespace(span data) + { + return ranges::all_of(data, [](unsigned char chr) { + return std::isspace(chr); + }); + } + + void handle_character_data(span data) override + { + if ( contains_only_whitespace(data) ) { + return; } - private: - ostream* pout_; - size_t depth_; - size_t indent_; + *pout_ << string(depth_ * indent_, ' ') << "Data: "; + pout_->write(data.data(), static_cast(data.size())); + *pout_ << '\n'; + } + +private: + ostream* pout_; + size_t depth_{}; + size_t indent_; }; int @@ -53,6 +83,6 @@ main() myxml.parse(cin); } catch ( exception& e ) { - cerr << "Fehler: " << e.what() << endl; + cerr << "Fehler: " << e.what() << '\n'; } } -- cgit v1.3