diff --git a/.idea/klib.iml b/.idea/klib.iml
index f08604b..d3f1e81 100644
--- a/.idea/klib.iml
+++ b/.idea/klib.iml
@@ -1,2 +1,8 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 79b3c94..ecaf8cc 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/Arena.cc b/Arena.cc
index 823b0f0..e9f1c56 100644
--- a/Arena.cc
+++ b/Arena.cc
@@ -1,19 +1,37 @@
-#include
+///
+/// \file Arena.cc
+/// \author K. Isom
+/// \date 2023-10-06
+/// \brief Memory management using an arena.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
+
#include
#include
#include
+
#if defined(__posix__) || defined(__linux__) || defined(__APPLE__)
#include
-#include
#include
#include
#include
#define PROT_RW (PROT_WRITE|PROT_READ)
-#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
-#include "WinHelpers.h"
-#pragma comment(lib, "advapi32.lib")
#endif
#include
@@ -246,7 +264,7 @@ Arena::Destroy()
case ArenaType::Static:
break;
case ArenaType::Alloc:
- delete this->store;
+ delete[] this->store;
break;
#if defined(__posix__) || defined(__linux__) || defined(__APPLE__)
case ArenaType::MemoryMapped:
diff --git a/Arena.h b/Arena.h
index 97b16c9..f57858d 100644
--- a/Arena.h
+++ b/Arena.h
@@ -1,11 +1,26 @@
///
/// \file Arena.h
-/// \author K. Isom
+/// \author K. Isom
/// \date 2023-10-06
/// \brief Memory management using an arena.
///
/// Arena defines a memory management backend for pre-allocating memory.
///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
/// \section PLATFORM SUPPORT
///
/// Arena will build on the major platforms, but memory-mapped files are only
@@ -17,10 +32,10 @@
#define KIMODEM_ARENA_H
-#include
-#include
#include
#include
+#include
+#include
#include "Exceptions.h"
@@ -112,12 +127,7 @@ public:
/// \param path The path to the file that should be created.
/// \param fileSize The size of the file to create.
/// \return Returns 0 on success and -1 on error.
-#if defined(__posix__) || defined(__linux__) || defined(__APPLE__)
int Create(const char *path, size_t fileSize);
-#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
- int Create(const char *path, size_t fileSize);
-
-#endif
/// Open reads a file into the arena; the file must already exist. On
/// Unix-based platforms, the arena will be backed by a memory via
diff --git a/Buffer.cc b/Buffer.cc
index 39e34b9..e062351 100644
--- a/Buffer.cc
+++ b/Buffer.cc
@@ -2,14 +2,28 @@
/// \file Buffer.cc
/// \author K. Isom
/// \date 2023-10-09
+/// \brief Buffer implements basic line buffers.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
///
-
#include
#include
#include
#include
-#include
#include "Buffer.h"
diff --git a/Buffer.h b/Buffer.h
index ba3c3b4..78b4034 100644
--- a/Buffer.h
+++ b/Buffer.h
@@ -8,12 +8,27 @@
/// editing. It allocates memory in powers of two, and will grow or shrink
/// as needed.
///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
#ifndef KGE_BUFFER_H
#define KGE_BUFFER_H
-#include
#include
+#include
namespace scsl {
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 99241bc..a7282b7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,64 +1,61 @@
cmake_minimum_required(VERSION 3.22)
project(scsl LANGUAGES CXX
- VERSION 0.1.1
+ VERSION 0.2.2
DESCRIPTION "Shimmering Clarity Standard Library")
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_VERBOSE_MAKEFILES TRUE)
set(VERBOSE YES)
-if (MSVC)
- add_compile_options("/W4" "$<$:/O2>")
+# compile options:
+# -Wall Default to all errors.
+# -Wextra And a few extra.
+# -Werror And require them to be fixed to build.
+# -Wno-unused-function This is a library. Not every function is used here.
+# -Wno-unused-parameter Some functions have parameters defined for compatibility,
+# and aren't used in the implementation.
+add_compile_options(
+ "-static"
+ "-Wall"
+ "-Wextra"
+ "-Werror"
+ "-Wno-unused-function"
+ "-Wno-unused-parameter"
+ "-g"
+ "$<$:-O2>"
+)
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ add_compile_options("-stdlib=libc++")
else ()
- # compile options:
- # -Wall Default to all errors.
- # -Wextra And a few extra.
- # -Werror And require them to be fixed to build.
- # -Wno-unused-function This is a library. Not every function is used here.
- # -Wno-unused-parameter Some functions have parameters defined for compatibility,
- # and aren't used in the implementation.
-
- add_compile_options(
- "-static"
- "-Wall"
- "-Wextra"
- "-Werror"
- "-Wno-unused-function"
- "-Wno-unused-parameter"
- "$<$:-O2>"
- )
- if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- add_compile_options("-stdlib=libc++")
- else ()
- # nothing special for gcc at the moment
- endif ()
+ # nothing special for gcc at the moment
endif ()
+
add_compile_definitions(SCSL_DESKTOP_BUILD)
add_compile_definitions(SCSL_VERSION=${PROJECT_VERSION})
set(HEADER_FILES scsl.h
Arena.h
Buffer.h
+ Commander.h
Dictionary.h
Exceptions.h
Flag.h
StringUtil.h
TLV.h
Test.h
- WinHelpers.h)
+)
set(SOURCE_FILES
Arena.cc
Buffer.cc
Commander.cc
- Commander.h
Dictionary.cc
Exceptions.cc
Flag.cc
StringUtil.cc
TLV.cc
Test.cc
- WinHelpers.cc)
+)
if (APPLE)
add_library(scsl
@@ -119,6 +116,6 @@ install(FILES ${HEADER_FILES} DESTINATION include/scsl)
install(FILES scslConfig.cmake DESTINATION share/scsl/cmake)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/scsl.pc DESTINATION lib/pkgconfig)
-include(CMakePack.txt)
-include(CMakeDocs.txt)
+include(cmake/packaging.cmake)
+include(cmake/docs.cmake)
endif()
diff --git a/Commander.cc b/Commander.cc
index dce29d9..cea9020 100644
--- a/Commander.cc
+++ b/Commander.cc
@@ -1,12 +1,30 @@
///
/// \file Commander.cc
-/// \author kyle
+/// \author K. Isom
/// \date 2023-10-10
+/// \brief Subprogram tooling.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
///
#include
+
#include "Commander.h"
+
namespace scsl {
@@ -57,4 +75,4 @@ Commander::Run(std::string command, int argc, char **argv)
}
-} // scsl
\ No newline at end of file
+} // namespace scsl
\ No newline at end of file
diff --git a/Commander.h b/Commander.h
index 4bfa7c0..280c3ad 100644
--- a/Commander.h
+++ b/Commander.h
@@ -12,9 +12,24 @@
/// $ some_tool subcommand args...
/// ```
///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
-#include
#include
+#include
#include
#include
@@ -28,7 +43,7 @@ namespace scsl {
/// CommanderFunc describes a function that can be run in Commander.
///
/// It expects an argument count and a list of arguments.
-typedef std::function CommanderFunc;
+using CommanderFunc = std::function;
/// Subcommands are the individual commands for the program. A Subcommand
@@ -104,7 +119,8 @@ private:
std::map cmap;
};
-} // scsl
+
+} // namespace scsl
#endif //SCSL_COMMANDER_H
diff --git a/Dictionary.cc b/Dictionary.cc
index 38f6d68..e491386 100644
--- a/Dictionary.cc
+++ b/Dictionary.cc
@@ -1,5 +1,28 @@
-#include
+///
+/// \file Dictionary.cc
+/// \author K.Isom
+/// \date 2023-10-05
+/// \brief Key-value store built on top of Arena and TLV.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
+
#include
+#include
+
#include "Dictionary.h"
#if defined(SCSL_DESKTOP_BUILD)
diff --git a/Dictionary.h b/Dictionary.h
index d259856..c28499c 100644
--- a/Dictionary.h
+++ b/Dictionary.h
@@ -1,7 +1,24 @@
///
-/// \file scsl.h
-/// \author kyle
-/// \date 2023-10-06
+/// \file Dictionary.h
+/// \author kyle (kyle@imap.cc)
+/// \date 2023-10-12
+/// \brief Key-value store built on top of Arena and TLV.
+///
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
///
@@ -9,6 +26,8 @@
#define SCSL_DICTIONARY_H
+#include
+
#include "Arena.h"
#include "TLV.h"
diff --git a/Exceptions.cc b/Exceptions.cc
index 3903b89..baf2d68 100644
--- a/Exceptions.cc
+++ b/Exceptions.cc
@@ -1,6 +1,24 @@
-//
-// Created by kyle on 2023-10-10.
-//
+///
+/// \file Exceptions.cc
+/// \author K. Isom
+/// \date 2023-10-10
+/// \brief Custom exceptions used in writing test programs.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
#include "Exceptions.h"
diff --git a/Exceptions.h b/Exceptions.h
index e4c9aaa..c4bab16 100644
--- a/Exceptions.h
+++ b/Exceptions.h
@@ -1,7 +1,24 @@
-//
-// Created by kyle on 2023-10-10.
-//
-
+///
+/// \file Exceptions.h
+/// \author K. Isom
+/// \date 2023-10-10
+/// \brief Custom exceptions for use in SCSL used in writing test programs.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
#ifndef SCSL_EXCEPTIONS_H
#define SCSL_EXCEPTIONS_H
@@ -9,6 +26,7 @@
#include
#include
+
namespace scsl {
diff --git a/Flag.cc b/Flag.cc
index a802f2c..e4cc56f 100644
--- a/Flag.cc
+++ b/Flag.cc
@@ -1,11 +1,9 @@
///
-/// \file Flag.h
-/// \author kyle
-/// \created 2023-10-12
+/// \file Flag.cc
+/// \author K. Isom
+/// \date 2023-10-12
/// \brief Flag defines a command-line flag parser.
///
-/// \section COPYRIGHT
-///
/// Copyright 2023 K. Isom
///
/// Permission to use, copy, modify, and/or distribute this software for
@@ -23,9 +21,7 @@
///
-#include
-#include
-#include
+#include
#include
#include
@@ -36,11 +32,11 @@
namespace scsl {
-static const std::regex isFlag("^--?[a-zA-Z0-9][a-zA-Z0-9-_]*$",
+static const std::regex isFlag("^--?[a-zA-Z0-9][a-zA-Z0-9-_]*$",
std::regex_constants::nosubs);
std::string
-ParseStatusToString(ParseStatus status)
+Flags::ParseStatusToString(ParseStatus status)
{
switch (status) {
case ParseStatus::OK:
@@ -58,22 +54,22 @@ ParseStatusToString(ParseStatus status)
Flag *
-NewFlag(FlagType fType, std::string fName, std::string fDescription)
+NewFlag(std::string fName, FlagType fType, std::string fDescription)
{
auto flag = new Flag;
- flag->Type = fType;
- flag->WasSet = false;
- flag->Name = fName;
+ flag->Type = fType;
+ flag->WasSet = false;
+ flag->Name = fName;
flag->Description = fDescription;
- flag->Value = FlagValue{};
+ flag->Value = FlagValue{};
return flag;
}
Flags::Flags(std::string fName)
- : name(fName), description("")
+ : name(fName), description("")
{
}
@@ -84,10 +80,21 @@ Flags::Flags(std::string fName, std::string fDescription)
}
+Flags::~Flags()
+{
+ for (auto flag : this->flags) {
+ if (flag.second->Type == FlagType::String) {
+ delete flag.second->Value.s;
+ }
+ delete flag.second;
+ }
+}
+
+
bool
Flags::Register(std::string fName, FlagType fType, std::string fDescription)
{
- if (!std::regex_search(fName, isFlag)) {
+ if (!std::regex_search(fName, isFlag) || fName == "-h") {
return false;
}
@@ -95,7 +102,7 @@ Flags::Register(std::string fName, FlagType fType, std::string fDescription)
return false;
}
- auto flag = NewFlag(fType, fName, fDescription);
+ auto flag = NewFlag(fName, fType, fDescription);
this->flags[fName] = flag;
return true;
}
@@ -191,12 +198,10 @@ Flags::ValueOf(std::string fName, FlagValue &value)
}
-
-ParseStatus
+Flags::ParseStatus
Flags::parseArg(int argc, char **argv, int &index)
{
- std::string arg(argv[index]);
-
+ std::string arg(argv[index]);
U::S::TrimWhitespace(arg);
index++;
@@ -205,29 +210,36 @@ Flags::parseArg(int argc, char **argv, int &index)
}
if (this->flags.count(arg) == 0) {
+ if (arg == "-h" || arg == "--help") {
+ Usage(std::cout, 0);
+ }
return ParseStatus::NotRegistered;
}
auto flag = flags[arg];
+ if ((flag->Type != FlagType::Boolean) && index == argc) {
+ return ParseStatus::NotEnoughArgs;
+ }
+
switch (flag->Type) {
case FlagType::Boolean:
- flag->WasSet = true;
+ flag->WasSet = true;
flag->Value.b = true;
return ParseStatus::OK;
case FlagType::Integer:
- flag->WasSet = true;
+ flag->WasSet = true;
flag->Value.i = std::stoi(argv[++index], 0, 0);
return ParseStatus::OK;
case FlagType::UnsignedInteger:
- flag->WasSet = true;
+ flag->WasSet = true;
flag->Value.u = static_cast(std::stoi(argv[index++], 0, 0));
return ParseStatus::OK;
case FlagType::String:
- flag->WasSet = true;
+ flag->WasSet = true;
flag->Value.s = new std::string(argv[index++]);
return ParseStatus::OK;
case FlagType::SizeT:
- flag->WasSet = true;
+ flag->WasSet = true;
flag->Value.size = static_cast(std::stoull(argv[index++]));
return ParseStatus::OK;
default:
@@ -242,10 +254,13 @@ Flags::parseArg(int argc, char **argv, int &index)
}
-ParseStatus
-Flags::Parse(int argc, char **argv)
+Flags::ParseStatus
+Flags::Parse(int argc, char **argv, bool skipFirst)
{
- int index = 1;
+ int index = 0;
+ if (skipFirst) {
+ index = 1;
+ }
while (index != argc) {
auto result = this->parseArg(argc, argv, index);
@@ -277,6 +292,55 @@ Flags::Parse(int argc, char **argv)
}
+void
+Flags::Usage(std::ostream &os, int exitCode)
+{
+ os << this->name << ":\t";
+ auto indent = this->name.size() + 7;
+
+ U::S::WriteTabIndented(os, description, 72 - indent, indent / 8, false);
+ os << "\n\n";
+
+ for (const auto &pair : this->flags) {
+ auto argLine = "\t" + pair.first;
+ switch (pair.second->Type) {
+ case FlagType::Boolean:
+ argLine += "\t\t";
+ break;
+ case FlagType::Integer:
+ argLine += "int\t\t";
+ break;
+ case FlagType::UnsignedInteger:
+ argLine += "uint\t\t";
+ break;
+ case FlagType::SizeT:
+ argLine += "size_t\t";
+ break;
+ case FlagType::String:
+ argLine += "string\t";
+ break;
+ case FlagType::Unknown:
+ // fallthrough
+ default:
+#ifdef SCSL_NOEXCEPT
+ abort();
+#else
+ throw std::runtime_error("unhandled parsing error - this is a bug");
+#endif
+ break;
+ }
+
+ os << argLine;
+ indent = argLine.size();
+ U::S::WriteTabIndented(os, pair.second->Description,
+ 72-indent, (indent/8)+2, false);
+ }
+
+ os << "\n";
+ exit(exitCode);
+}
+
+
size_t
Flags::NumArgs()
{
@@ -291,6 +355,17 @@ Flags::Args()
}
+std::string
+Flags::Arg(size_t i)
+{
+ if (i >= this->args.size()) {
+ throw std::out_of_range("index is out of range");
+ }
+
+ return this->args[i];
+}
+
+
Flag *
Flags::checkGetArg(std::string fName, FlagType eType)
{
@@ -314,7 +389,7 @@ Flags::checkGetArg(std::string fName, FlagType eType)
bool
Flags::GetBool(std::string fName, bool &flagValue)
{
- auto flag = this->checkGetArg(fName, FlagType::Boolean);
+ auto flag = this->checkGetArg(fName, FlagType::Boolean);
flagValue = flag->Value.b;
return flag->WasSet;
@@ -324,7 +399,7 @@ Flags::GetBool(std::string fName, bool &flagValue)
bool
Flags::GetInteger(std::string fName, int &flagValue)
{
- auto flag = this->checkGetArg(fName, FlagType::Integer);
+ auto flag = this->checkGetArg(fName, FlagType::Integer);
flagValue = flag->Value.i;
return flag->WasSet;
@@ -334,18 +409,17 @@ Flags::GetInteger(std::string fName, int &flagValue)
bool
Flags::GetUnsignedInteger(std::string fName, unsigned int &flagValue)
{
- auto flag = this->checkGetArg(fName, FlagType::UnsignedInteger);
+ auto flag = this->checkGetArg(fName, FlagType::UnsignedInteger);
flagValue = flag->Value.u;
return flag->WasSet;
}
-
bool
Flags::GetSizeT(std::string fName, std::size_t &flagValue)
{
- auto flag = this->checkGetArg(fName, FlagType::SizeT);
+ auto flag = this->checkGetArg(fName, FlagType::SizeT);
flagValue = flag->Value.size;
return flag->WasSet;
@@ -355,7 +429,7 @@ Flags::GetSizeT(std::string fName, std::size_t &flagValue)
bool
Flags::GetString(std::string fName, std::string &flagValue)
{
- auto flag = this->checkGetArg(fName, FlagType::String);
+ auto flag = this->checkGetArg(fName, FlagType::String);
if (flag->Value.s == nullptr) {
return false;
diff --git a/Flag.h b/Flag.h
index d009ac1..cd50903 100644
--- a/Flag.h
+++ b/Flag.h
@@ -1,11 +1,9 @@
///
/// \file Flag.h
-/// \author kyle
-/// \created 2023-10-12
+/// \author K. Isom
+/// \date 2023-10-12
/// \brief Flag declares a command-line flag parser.
///
-/// \section COPYRIGHT
-///
/// Copyright 2023 K. Isom
///
/// Permission to use, copy, modify, and/or distribute this software for
@@ -35,90 +33,297 @@ namespace scsl {
/// FlagType indicates the value held in a FlagValue.
+///
+/// \todo When C++17 support is more common, switch to `std::variant`.
enum class FlagType : uint8_t {
- Unknown = 0,
- Boolean = 1,
+ Unknown = 0, ///< Unsupported value type.
+ Boolean = 1, ///< bool
Integer = 2, ///< int32_t
UnsignedInteger = 3, ///< uint32_t
SizeT = 4, ///< size_t
- String = 5,
+ String = 5, ///< std::string
};
-enum class ParseStatus : uint8_t {
- Unknown = 0,
- OK = 1,
- EndOfFlags = 2,
- NotRegistered = 3,
- NotEnoughArgs = 4,
-};
-
-std::string
-ParseStatusToString(ParseStatus status);
-
-
+/// FlagValue holds the value of a command line flag.
typedef union {
- unsigned int u;
- int i;
- std::size_t size;
- std::string *s;
- bool b;
+ unsigned int u; ///< FlagType::UnsignedInteger
+ int i; ///< FlagType::Integer
+ std::size_t size; ///< FlagType::SizeT
+ std::string *s; ///< FlagType::String
+ bool b; ///< FlagType::Boolean
} FlagValue;
+/// Flag describes an individual command-line flag.
typedef struct {
- FlagType Type;
- bool WasSet;
- std::string Name;
- std::string Description;
- FlagValue Value;
+ FlagType Type; ///< The type of the value in the flag.
+ bool WasSet; ///< The flag was set on the command-line.
+ std::string Name; ///< The name of the flag.
+ std::string Description; ///< A description of the flag.
+ FlagValue Value; ///< The flag's value.
} Flag;
-Flag *
-NewFlag(FlagType fType, std::string fName, std::string fDescription);
-
+/// NewFlag is a helper function for constructing a new flag.
+///
+/// \param fName The name of the flag.
+/// \param fType The type of the flag.
+/// \param fDescription A description of the flag.
+/// \return A pointer to a flag.
+Flag *NewFlag(std::string fName, FlagType fType, std::string fDescription);
+/// Flags provides a basic facility for processing command line flags.
+///
+/// Any remaining arguments after the args are added to the parser as
+/// arguments that can be accessed with NumArgs, Args, and Arg.
+///
+/// \note The parser automatically handles the -h and --help flags by
+/// calling Usage(std::cout, 0). The user can override this flag
+/// and handle providing help on their own.
+///
+/// \details
+///
+/// Arguments are named with their leading dash, e.g. "-f". For example,
+///
+/// ```c++
+/// flags.Register("-f", FlagType::String, "Path to a configuration file.");
+/// ```
+/// \section Usage
+///
+/// A short example program is below:
+///
+/// int
+/// main(int argc, char *argv[])
+/// {
+/// std::string server = "service.example.com";
+/// unsigned int port = 1234;
+///
+/// auto flags = new scsl::Flags("example-client",
+/// "This interacts with the example.com service.");
+/// flags->Register("-p", port, "server port");
+/// flags->Register("-s", server, "hostname to connect to");
+///
+/// auto status = flags->Parse(argc, argv);
+/// if (status != ParseStatus::OK) {
+/// std::cerr << "failed to parse flags: "
+/// << scsl::Flags::ParseStatusToString(status)
+/// << "\n";
+/// exit(1);
+/// }
+///
+/// auto wasSet = flags->GetString("-s", server);
+/// if (wasSet) {
+/// std::cout << "hostname override: " << server << "\n";
+/// }
+///
+/// wasSet = flags->GetUnsignedInteger("-p", port);
+/// if (wasSet) {
+/// std::cout << "port override: " << port << "\n";
+/// }
+///
+/// std::cout << "connecting to " << server << ":" << port << "\n";
+/// for (size_t i = 0; i < flags.NumArgs(); i++) {
+/// std::cout << "\tExecuting command " << flags.Arg(i) << "\n";
+/// }
+/// return 0;
+/// }
+///
class Flags {
public:
+ /// ParseStatus describes the result of parsing command-line
+ /// arguments.
+ enum class ParseStatus : uint8_t {
+ /// An unknown parsing error occurred. This is a bug,
+ /// and users should never see this.
+ Unknown = 0,
+
+ /// Parsing succeeded.
+ OK = 1,
+
+ /// This is an internal status marking the end of
+ /// command line flags.
+ EndOfFlags = 2,
+
+ /// The command line flag provided isn't registered.
+ NotRegistered = 3,
+
+ /// Not enough arguments were provided to a flag that
+ /// takes an argument. For example, if "-p" expects
+ /// a number, and the program was called with just
+ /// `./program -p`, this error will be reported.
+ NotEnoughArgs = 4,
+ };
+
+ /// ParseStatusToString returns a string message describing the
+ /// result of parsing command line args.
+ static std::string ParseStatusToString(ParseStatus status);
+
+ /// Create a new flags parser for the named program.
+ ///
+ /// \param fName The program name,
Flags(std::string fName);
+
+ /// Create a new flags parser for the named program.
+ ///
+ /// \param fName The program name.
+ /// \param fDescription A short description of the program.
Flags(std::string fName, std::string fDescription);
+ ~Flags();
+
+ /// Register a new command line flag.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param fType The type of the argument to parse.
+ /// \param fDescription A description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
FlagType fType,
std::string fDescription);
+
+ /// Register a new boolean command line flag with a default value.
+ ///
+ /// \note For booleans, it only makes sense to pass a false default
+ /// value, as there is no way to set a boolean flag to false.
+ /// This form is provided for compatibility with the other
+ /// variants on this method.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param defaultValue The default value for the flag.
+ /// \param fDescription A short description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
bool defaultValue,
std::string fDescription);
+
+ /// Register a new integer command line flag with a default value.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param defaultValue The default value for the flag.
+ /// \param fDescription A short description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
int defaultValue,
std::string fDescription);
+
+ /// Register a new unsigned integer command line flag with a default
+ /// value.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param defaultValue The default value for the flag.
+ /// \param fDescription A short description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
unsigned int defaultValue,
std::string fDescription);
+
+ /// Register a new size_t command line flag with a default value.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param defaultValue The default value for the flag.
+ /// \param fDescription A short description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
size_t defaultValue,
std::string fDescription);
+
+ /// Register a new string command line flag with a default value.
+ ///
+ /// \param fName The name of the flag, including a leading dash.
+ /// \param defaultValue The default value for the flag.
+ /// \param fDescription A short description of the flag.
+ /// \return True if the flag was registered, false if the flag could
+ /// not be registered (e.g. a duplicate flag was registered).
bool Register(std::string fName,
std::string defaultValue,
std::string fDescription);
+
+ /// Return the number of registered flags.
size_t Size();
+
+ /// Lookup a flag.
+ ///
+ /// \param fName The flag name.
+ /// \return A pointer to flag if registered, or nullptr if the flag
+ /// wasn't registered.
Flag *Lookup(std::string fName);
+
+ /// ValueOf returns the value of the flag in the
bool ValueOf(std::string fName, FlagValue &value);
- ParseStatus Parse(int argc, char **argv);
+ /// Process a list of arguments into flags.
+ ///
+ /// \param argc The number of arguments.
+ /// \param argv The arguments passed to the program.
+ /// \param skipFirst Flags expects to receive arguments directly
+ /// from those passed to `main`, and defaults to skipping
+ /// the first argument. Set to false if this is not the
+ /// case.
+ /// \return
+ ParseStatus Parse(int argc, char **argv, bool skipFirst=true);
+ /// Print a usage message to the output stream.
void Usage(std::ostream &os, int exitCode);
+ /// Return the number of arguments processed. These are any
+ /// remaining elements in argv that are not flags.
size_t NumArgs();
+
+ /// Return the arguments as a vector.
std::vector Args();
- std::string Arg(int index);
+ /// Return a particular argument.
+ ///
+ /// \param index The argument number to extract.
+ /// \return The argument at index i. If the index is greater than
+ /// the number of arguments present, an out_of_range
+ /// exception is thrown.
+ std::string Arg(size_t index);
+
+ /// Retrieve the state of a boolean flag.
+ ///
+ /// \param fName The flag to look up.
+ /// \param flagValue The value to store.
+ /// \return True if the value was set, or false if the value isn't
+ /// a boolean or if it wasn't set.
bool GetBool(std::string fName, bool &flagValue);
- bool GetUnsignedInteger(std::string fName, unsigned int &flagValue);
- bool GetInteger(std::string fName, int &flagValue);
- bool GetString(std::string fName, std::string &flagValue);
- bool GetSizeT(std::string fName, std::size_t &flagValue);
+ /// Retrieve the value of an unsigned integer flag.
+ ///
+ /// \param fName The flag to look up.
+ /// \param flagValue The value to store.
+ /// \return True if the value was set, or false if the value isn't
+ /// an unsigned integer or if it wasn't set.
+ bool GetUnsignedInteger(std::string fName, unsigned int &flagValue);
+
+ /// Retrieve the value of an integer flag.
+ ///
+ /// \param fName The flag to look up.
+ /// \param flagValue The value to store.
+ /// \return True if the value was set, or false if the value isn't
+ /// an integer or if it wasn't set.
+ bool GetInteger(std::string fName, int &flagValue);
+
+ /// Retrieve the value of a string flag.
+ ///
+ /// \param fName The flag to look up.
+ /// \param flagValue The value to store.
+ /// \return True if the value was set, or false if the value isn't
+ /// a string or if it wasn't set.
+ bool GetString(std::string fName, std::string &flagValue);
+
+ /// Retrieve the value of a size_t flag.
+ ///
+ /// \param fName The flag to look up.
+ /// \param flagValue The value to store.
+ /// \return True if the value was set, or false if the value isn't
+ /// a size_t or if it wasn't set.
+ bool GetSizeT(std::string fName, std::size_t &flagValue);
private:
ParseStatus parseArg(int argc, char **argv, int &index);
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..56fb9c4
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright 2023 K. Isom
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 8852cd0..d152258 100644
--- a/Makefile
+++ b/Makefile
@@ -1,39 +1,59 @@
-TARGET := klib.a
-TESTS := tlv_test dictionary_test
-HEADERS := $(wildcard *.h)
-SOURCES := $(wildcard *.cc)
-OBJS := Arena.o Dictionary.o TLV.o
+HEADERS := scsl.h \
+ Arena.h \
+ Buffer.h \
+ Commander.h \
+ Dictionary.h \
+ Exceptions.h \
+ Flag.h \
+ StringUtil.h \
+ Test.h \
+ TLV.h \
+ WinHelpers.h
+SOURCES := Arena.cc \
+ Buffer.cc \
+ Commander.cc \
+ Dictionary.cc \
+ Exceptions.cc \
+ Flag.cc \
+ StringUtil.cc \
+ Test.cc \
+ TLV.cc \
+ WinHelpers.cc
+
+BUILD := DEBUG
+OBJS := $(patsubst %.cc,%.o,$(SOURCES))
+LIBS := libscsl.a
+
+TARGETS := $(LIBS) phonebook
+TESTS := bufferTest dictionaryTest flagTest tlvTest
CXX := clang++
-CXXFLAGS := -g -std=c++14 -Werror -Wall -DSCSL_DESKTOP_BUILD
+CXXFLAGS := -std=c++14 -Werror -Wall -Wextra -DSCSL_DESKTOP_BUILD \
+ -DSCSL_BUILD_TYPE=${BUILD}
+ifeq ($(BUILD),DEBUG)
+CXXFLAGS += -g -fsanitize=address
+else
+CXXFLAGS += -O2
+endif
.PHONY: all
-all: $(TARGET) $(TESTS) tags run-tests
+all: $(TARGETS) $(TESTS) tags run-tests
tags: $(HEADERS) $(SOURCES)
ctags $(HEADERS) $(SOURCES)
-$(TARGET): $(OBJS)
+libscsl.a: $(OBJS)
$(AR) rcs $@ $(OBJS)
-tlv_test: tlvTest.o $(TARGET)
- $(CXX) -o $@ $(CXXFLAGS) tlvTest.o $(TARGET)
-
-dictionary_test: dictionaryTest.o $(TARGET)
- $(CXX) -o $@ $(CXXFLAGS) dictionaryTest.o $(TARGET)
-
.PHONY: print-%
print-%: ; @echo '$(subst ','\'',$*=$($*))'
klib.a: $(OBJS)
-%.o: %.cc
- $(CXX) -o $@ -c $(CXXFLAGS) $<
-
.PHONY: clean
clean:
# build outputs
- rm -f $(TARGET) $(TESTS) *.o
+ rm -f $(TARGETS) $(TESTS) *.o
# test miscellaneous
rm -f core core.* tags arena_test.bin
@@ -45,3 +65,22 @@ run-tests: $(TESTS)
echo "./$${testbin}" ; \
./$${testbin}; \
done
+
+phonebook: phonebook.o $(LIBS)
+ $(CXX) -o $@ $(CXXFLAGS) $@.o $(LIBS)
+
+bufferTest: bufferTest.o $(LIBS)
+ $(CXX) -o $@ $(CXXFLAGS) $@.o $(LIBS)
+
+dictionaryTest: dictionaryTest.o $(LIBS)
+ $(CXX) -o $@ $(CXXFLAGS) $@.o $(LIBS)
+
+flagTest: flagTest.o $(LIBS)
+ $(CXX) -o $@ $(CXXFLAGS) $@.o $(LIBS)
+
+tlvTest: tlvTest.o $(LIBS)
+ $(CXX) -o $@ $(CXXFLAGS) $@.o $(LIBS)
+
+%.o: %.cc
+ $(CXX) -o $@ -c $(CXXFLAGS) $<
+
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..552001d
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,27 @@
+scsl : The Shimmering Clarity Standard C++ Library
+==================================================
+
+scsl is a collection of software I found myself needing to use repeatedly.
+
+Full `Doxygen documentation`_ is available.
+
+.. _Doxygen documentation: https://docs.shimmering-clarity.net/scsl/
+
+
+License
+-------
+
+Copyright 2023 K. Isom
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/StringUtil.cc b/StringUtil.cc
index 778e444..c702fe8 100644
--- a/StringUtil.cc
+++ b/StringUtil.cc
@@ -1,3 +1,26 @@
+///
+/// \file StringUtil.cc
+/// \author K. Isom
+/// \date 2023-10-12
+/// \brief Utilities for working with strings.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
+
+#include
#include
#include
@@ -12,22 +35,21 @@ namespace U {
namespace S {
-/*
std::vector
SplitKeyValuePair(std::string line, std::string delimiter)
{
- std::string key;
- std::string val;
+ auto pair = SplitN(line, delimiter, 2);
- auto pos = line.find(delimiter);
- if (pos == std::string::npos) {
- key = line;
- val = "";
- } else {
- key = line.substr(0, pos);
- val = line.substr(pos + 1, line.size() - pos - 2);
+ if (pair.size() == 0) {
+ return {"", ""};
+ } else if (pair.size() == 1) {
+ return {pair[0], ""};
}
+ assert(pair.size() == 2);
+ auto key = pair[0];
+ auto val = pair[1];
+
TrimWhitespace(key);
TrimWhitespace(val);
return {key, val};
@@ -37,23 +59,11 @@ SplitKeyValuePair(std::string line, std::string delimiter)
std::vector
SplitKeyValuePair(std::string line, char delimiter)
{
- std::string key;
- std::string val;
+ std::string sDelim;
- auto pos = line.find(delimiter);
- if (pos == std::string::npos) {
- key = line;
- val = "";
- } else {
- key = line.substr(0, pos);
- val = line.substr(pos + 1, line.size() - pos - 2);
- }
-
- TrimWhitespace(key);
- TrimWhitespace(val);
- return {key, val};
+ sDelim.push_back(delimiter);
+ return SplitKeyValuePair(line, sDelim);
}
-*/
void
@@ -132,6 +142,66 @@ SplitN(std::string s, std::string delim, size_t maxCount)
}
+std::vector
+WrapText(std::string line, size_t lineLength)
+{
+ std::vector wrapped;
+ auto parts = SplitN(line, " ", 0);
+
+ for (auto &part: parts) {
+ TrimWhitespace(part);
+
+ }
+
+ std::string wLine;
+ for (auto word: parts) {
+ if (word.size() == 0) {
+ continue;
+ }
+
+ if ((wLine.size() + word.size() + 1) > lineLength) {
+ wrapped.push_back(wLine);
+ wLine.clear();
+ }
+
+ if (wLine.size() > 0) {
+ wLine += " ";
+ }
+ wLine += word;
+ }
+
+ if (wLine.size() > 0) {
+ wrapped.push_back(wLine);
+ }
+
+ return wrapped;
+}
+
+
+void
+WriteTabIndented(std::ostream &os, std::vector lines,
+ int tabStop, bool indentFirst)
+{
+ std::string indent(tabStop, '\t');
+
+ for (size_t i = 0; i < lines.size(); i++) {
+ if (i > 0 || indentFirst) {
+ os << indent;
+ }
+ os << lines[i] << "\n";
+ }
+}
+
+
+void
+WriteTabIndented(std::ostream &os, std::string line, size_t maxLength,
+ int tabStop, bool indentFirst)
+{
+ auto lines = WrapText(line, maxLength);
+ WriteTabIndented(os, lines, tabStop, indentFirst);
+}
+
+
std::ostream &
VectorToString(std::ostream &os, const std::vector &svec)
{
@@ -141,7 +211,7 @@ VectorToString(std::ostream &os, const std::vector &svec)
os << "{";
for (size_t i = 0; i < svec.size(); i++) {
- if (i > 0) os << ", ";
+ if (i > 0) { os << ", "; }
os << svec[i];
}
@@ -153,7 +223,7 @@ VectorToString(std::ostream &os, const std::vector &svec)
std::string
VectorToString(const std::vector &svec)
{
- std::stringstream ss;
+ std::stringstream ss;
VectorToString(ss, svec);
return ss.str();
diff --git a/StringUtil.h b/StringUtil.h
index a32b657..083cd50 100644
--- a/StringUtil.h
+++ b/StringUtil.h
@@ -1,10 +1,9 @@
///
/// \file StringUtil.h
-/// \author kyle (kyle@midgard)
-/// \created 2023-10-14
-/// \brief StringUtil contains string utilities.
+/// \author K. Isom
+/// \date 2023-10-14
+/// \brief Utilities for working with strings.
///
-/// \section COPYRIGHT
/// Copyright 2023 K. Isom
///
/// Permission to use, copy, modify, and/or distribute this software for
@@ -85,17 +84,44 @@ std::vector SplitKeyValuePair(std::string line, char delimiter);
/// Split a string into parts based on the delimiter.
///
+/// \param s The string that should be split.
/// \param delimiter The string that delimits the parts of the string.
-/// \param maxCount The maximum number of parts to split. If 0, there is no limit
-/// to the number of parts.
+/// \param maxCount The maximum number of parts to split. If 0, there is no
+/// limit to the number of parts.
/// \return A vector containing all the parts of the string.
std::vector SplitN(std::string, std::string delimiter, size_t maxCount=0);
-//std::vector SplitN(std::string, char delimiter, size_t size_t maxCount=0);
+/// WrapText is a very simple wrapping function that breaks the line into
+/// lines of at most lineLength characters. It does this by breaking the
+/// line into individual words (splitting on whitespace).
+std::vector WrapText(std::string line, size_t lineLength);
+
+/// Write out a vector of lines indented with tabs.
+///
+/// \param os The output stream to write to.
+/// \param lines The lines of text to write.
+/// \param tabStop The number of tabs to indent.
+/// \param indentFirst Whether the first line should be indented.
+void WriteTabIndented(std::ostream &os, std::vector lines,
+ int tabStop, bool indentFirst);
+
+/// Wrap a line, then output it to a stream.
+///
+/// \param os The output stream to write to.
+/// \param line The line to wrap and output.
+/// \param maxLength The maximum length of each section of text.
+/// \param tabStop The number of tabs to indent.
+/// \param indentFirst Whether the first line should be indented.
+void WriteTabIndented(std::ostream &os, std::string line, size_t maxLength,
+ int tabStop, bool indentFirst);
-/// Return a string represention of a string vector in the form [size]{"foo", "bar", ...}.
+/// Write a string vector to the output stream in the same format as
+/// VectorToString.
std::ostream &VectorToString(std::ostream &os, const std::vector &svec);
+
+/// Return a string represention of a string vector in the form
+/// [size]{"foo", "bar", ...}.
std::string VectorToString(const std::vector &svec);
diff --git a/TLV.cc b/TLV.cc
index 44401b1..2fccf2a 100644
--- a/TLV.cc
+++ b/TLV.cc
@@ -1,9 +1,35 @@
+///
+/// \file TLV.cc
+/// \author K. Isom
+/// \date 2023-10-06
+/// \brief Tag-Length-Value records built on Arena.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
+
+#include
#include
+
#include "TLV.h"
using namespace scsl;
+/// REC_SIZE calculates the total length of a TLV record, including the
+/// two byte header.
#define REC_SIZE(x) ((std::size_t)x.Len + 2)
@@ -90,6 +116,7 @@ FindTag(Arena &arena, uint8_t *cursor, Record &rec)
{
cursor = LocateTag(arena, cursor, rec);
if (rec.Tag != TAG_EMPTY) {
+ std::cout << "skipping record\n";
cursor = SkipRecord(rec, cursor);
}
@@ -102,13 +129,22 @@ LocateTag(Arena &arena, uint8_t *cursor, Record &rec)
{
uint8_t tag, len;
+ if (!arena.CursorInArena(cursor)) {
+ cursor = nullptr;
+ }
+
if (cursor == nullptr) {
+ std::cout << "move cursor to arena start\n";
cursor = arena.Start();
}
while ((tag = cursor[0]) != rec.Tag) {
+ assert(arena.CursorInArena(cursor));
+ std::cout << "cursor is in arena\n";
len = cursor[1];
+ std::cout << "record length" << len << "\n";
if (!spaceAvailable(arena, cursor, len)) {
+ std::cout << "no space available\n";
return nullptr;
}
cursor += len;
diff --git a/TLV.h b/TLV.h
index 0821217..50ec427 100644
--- a/TLV.h
+++ b/TLV.h
@@ -14,8 +14,8 @@
#ifndef KIMODEM_TLV_H
#define KIMODEM_TLV_H
-#include
#include
+#include
#include "Arena.h"
@@ -23,6 +23,7 @@
namespace scsl {
namespace TLV {
+
#ifndef TLV_MAX_LEN
static constexpr size_t TLV_MAX_LEN = 253;
#endif
diff --git a/Test.cc b/Test.cc
index 15605de..44042c5 100644
--- a/Test.cc
+++ b/Test.cc
@@ -1,11 +1,28 @@
-//
-// Created by kyle on 2023-10-09.
-//
+///
+/// \file Test.cc
+/// \author K. Isom
+/// \date 2023-10-09
+/// \brief Tooling to assist in building test programs..
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
#include "Exceptions.h"
#include "Test.h"
-#include
#include
#include
diff --git a/Test.h b/Test.h
index 12f2c5b..68a3393 100644
--- a/Test.h
+++ b/Test.h
@@ -2,11 +2,28 @@
/// \file Test.h
/// \author K. Isom
/// \date 2023-10-09
-/// \brief Test.h implements basic testing tools.
+/// \brief Tooling to assist in building test programs..
///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
+
#ifndef SCSL_TEST_H
#define SCSL_TEST_H
+
#include
diff --git a/WinHelpers.cc b/WinHelpers.cc
deleted file mode 100644
index 7420e12..0000000
--- a/WinHelpers.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-// Created by kyle on 2023-10-10.
-//
-
-#if defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
-
-#include "WinHelpers.h"
-
-
-namespace scsl {
-namespace Windows {
-
-
-int
-DisplayWinError(LPTSTR lpszFunction, HANDLE handle)
-{
- // Retrieve the system error message for the last-error code
- DWORD dw = GetLastError();
-#ifndef NDEBUG
- LPVOID lpMsgBuf;
- LPVOID lpDisplayBuf;
-
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- dw,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0, NULL);
-
- // Display the error message and exit the process
- lpDisplayBuf = (LPVOID) LocalAlloc(LMEM_ZEROINIT,
- (lstrlen((LPCTSTR) lpMsgBuf) +
- lstrlen((LPCTSTR) lpszFunction) +
- 40) * sizeof(TCHAR));
- StringCchPrintf((LPTSTR) lpDisplayBuf,
- LocalSize(lpDisplayBuf) / sizeof(TCHAR),
- TEXT("%s failed with error %d: %s"),
- lpszFunction, dw, lpMsgBuf);
- MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
-
- LocalFree(lpMsgBuf);
- LocalFree(lpDisplayBuf);
-#endif
- if ((handle != NULL) && (handle != INVALID_HANDLE_VALUE)) {
- CloseHandle(handle);
- }
- return dw;
-}
-
-
-BOOL SetPrivilege(
- HANDLE hToken, // access token handle
- LPCTSTR lpszPrivilege, // name of privilege to enable/disable
- BOOL bEnablePrivilege // to enable or disable privilege
-)
-{
- TOKEN_PRIVILEGES tp;
- LUID luid;
-
- if (!LookupPrivilegeValue(
- NULL, // lookup privilege on local system
- lpszPrivilege, // privilege to lookup
- &luid)) // receives LUID of privilege
- {
- printf("LookupPrivilegeValue error: %u\n", GetLastError());
- return FALSE;
- }
-
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- if (bEnablePrivilege)
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- else
- tp.Privileges[0].Attributes = 0;
-
- // Enable the privilege or disable all privileges.
-
- if (!AdjustTokenPrivileges(
- hToken,
- FALSE,
- &tp,
- sizeof(TOKEN_PRIVILEGES),
- (PTOKEN_PRIVILEGES) NULL,
- (PDWORD) NULL)) {
- printf("AdjustTokenPrivileges error: %u\n", GetLastError());
- return FALSE;
- }
-
- if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
- printf("The token does not have the specified privilege. \n");
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-HANDLE
-CreateFileWindows(const char *path)
-{
- HANDLE fHandle;
-
- return CreateFileA(
- (LPSTR) path,
- (GENERIC_READ | GENERIC_WRITE),
- (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE),
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-}
-
-
-int
-CreateFixedSizeFile(const char *path, size_t size)
-{
- _LARGE_INTEGER fileSize;
-
- fileSize.QuadPart = size;
-
- HANDLE fHandle = CreateFileWindows(path);
- if (SetFilePointerEx(fHandle, fileSize, nullptr, FILE_BEGIN) != TRUE) {
- return DisplayWinError("SetFilePointerEx", fHandle);
- }
-
- if (SetEndOfFile(fHandle) != TRUE) {
- return DisplayWinError("SetEndOfFile", fHandle);
- }
-
- CloseHandle(fHandle);
- return 0;
-}
-
-
-} // namespace Windows
-} // namespace scsl
-
-
-#endif
\ No newline at end of file
diff --git a/WinHelpers.h b/WinHelpers.h
deleted file mode 100644
index e00b98d..0000000
--- a/WinHelpers.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Created by kyle on 2023-10-10.
-//
-
-#ifndef SCSL_WINHELPERS_H
-#define SCSL_WINHELPERS_H
-
-#if defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
-
-#include
-#include
-#include
-#include
-
-namespace scsl {
-namespace Windows {
-
-
-int DisplayWinError(LPTSTR lpszFunction, HANDLE handle);
-
-BOOL SetPrivilege(
- HANDLE hToken, // access token handle
- LPCTSTR lpszPrivilege, // name of privilege to enable/disable
- BOOL bEnablePrivilege // to enable or disable privilege
-);
-
-HANDLE CreateFileWindows(const char *path);
-
-int CreateFixedSizeFile(const char *path, size_t size);
-
-
-
-
-} // namespace Windows
-} // namespace scsl
-
-#endif // Windows-only guards.
-
-#endif //SCSL_WINHELPERS_H
diff --git a/CMakeDocs.txt b/cmake/docs.cmake
similarity index 93%
rename from CMakeDocs.txt
rename to cmake/docs.cmake
index a49bb53..6fa44db 100644
--- a/CMakeDocs.txt
+++ b/cmake/docs.cmake
@@ -4,7 +4,7 @@ find_package(Doxygen)
if (${DOXYGEN_FOUND})
set(DOXYGEN_GENERATE_MAN YES)
set(DOXYGEN_GENERATE_LATEX YES)
-#set(DOXYGEN_EXTRACT_ALL YES)
+set(DOXYGEN_EXTRACT_ALL YES)
message(STATUS "Doxygen found, building docs.")
doxygen_add_docs(scsl_docs
diff --git a/CMakePack.txt b/cmake/packaging.cmake
similarity index 89%
rename from CMakePack.txt
rename to cmake/packaging.cmake
index d0fbbd2..5e620ec 100644
--- a/CMakePack.txt
+++ b/cmake/packaging.cmake
@@ -7,6 +7,9 @@ set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
+set(CPACK_PACKAGE_FILE_NAME
+ ${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_ARCH}${CMAKE_HOST_SYSTEM_PROCESSOR})
+
# Debian settings
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Shimmering Clarity")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "The Shimmering Clarity standard C++ library")
@@ -35,4 +38,3 @@ set(CPACK_SOURCE_IGNORE_FILES
include (CPack)
add_custom_target(package_docs DEPENDS SCSL_docs package package_source)
-
diff --git a/flagTest.cc b/flagTest.cc
index 77002a4..a465893 100644
--- a/flagTest.cc
+++ b/flagTest.cc
@@ -20,18 +20,19 @@ main(int argc, char *argv[])
int testInteger = 0;
std::string testString;
- auto flags = new Flags("flag_test", "this is a test of the flag functionality.");
+ auto flags = new Flags("flag_test", "this is a test of the flag functionality. This line is particularly long to make sure the wrapping works.");
flags->Register("-b", FlagType::Boolean, "test boolean");
flags->Register("-s", FlagType::String, "test string");
- flags->Register("-u", (unsigned int)42, "test unsigned integer");
+ flags->Register("-u", (unsigned int)42, "test unsigned integer with a long description line. This should trigger multiline text-wrapping.");
flags->Register("-i", -42, "test integer");
flags->Register("-size", FlagType::SizeT, "test size_t");
TestAssert(flags->Size() == 5, "flags weren't registered");
auto status = flags->Parse(argc, argv);
- if (status != ParseStatus::OK) {
- std::cerr << "failed to parse flags: " << ParseStatusToString(status) << "\n";
+ if (status != Flags::ParseStatus::OK) {
+ std::cerr << "failed to parse flags: "
+ << Flags::ParseStatusToString(status) << "\n";
exit(1);
}
@@ -55,5 +56,6 @@ main(int argc, char *argv[])
std::cout << "(string) test flag was set: " << wasSet << "\n";
std::cout << "(string) test flag value: " << testString << "\n";
+ delete flags;
return 0;
}
\ No newline at end of file
diff --git a/phonebook.cc b/phonebook.cc
index 46223ab..8434be8 100644
--- a/phonebook.cc
+++ b/phonebook.cc
@@ -1,6 +1,24 @@
-//
-// Created by kyle on 2023-10-10.
-//
+///
+/// \file phonebook.cc
+/// \author K. Isom
+/// \date 2023-10-10
+/// \brief Commandline tools for interacting with dictionary data file.
+///
+/// Copyright 2023 K. Isom
+///
+/// Permission to use, copy, modify, and/or distribute this software for
+/// any purpose with or without fee is hereby granted, provided that
+/// the above copyright notice and this permission notice appear in all /// copies.
+///
+/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
+/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+/// PERFORMANCE OF THIS SOFTWARE.
+///
#include
#include
@@ -9,6 +27,7 @@ using namespace std;
#include "Arena.h"
#include "Commander.h"
#include "Dictionary.h"
+#include "Flag.h"
using namespace scsl;
static const char *defaultPhonebook = "pb.dat";
diff --git a/scsl.h b/scsl.h
index cb0d763..d1bee0b 100644
--- a/scsl.h
+++ b/scsl.h
@@ -1,10 +1,13 @@
///
/// \file scsl.h
-/// \author kyle
-/// \created 2023-10-10
+/// \author kyle (kyle@imap.cc)
+/// \date 2023-10-10
/// \brief scsl is my collection of C++ data structures and code.
///
+/// scsl.h is a utility header that includes all of SCSL.
+///
/// \section COPYRIGHT
+///
/// Copyright 2023 K. Isom
///
/// Permission to use, copy, modify, and/or distribute this software for
@@ -25,12 +28,15 @@
#define SCSL_SCSL_H
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
/// scsl is the top-level namespace containing all the code in this library.
diff --git a/stringutil_test.cc b/stringutil_test.cc
index 9f7d2ea..3740817 100644
--- a/stringutil_test.cc
+++ b/stringutil_test.cc
@@ -1,10 +1,9 @@
///
/// \file stringutil_test.cc
/// \author kyle
-/// \created 10/14/23
+/// \date 10/14/23
/// \brief Ensure the stringutil functions work.
///
-/// \section COPYRIGHT
/// Copyright 2023 K. Isom
///
/// Permission to use, copy, modify, and/or distribute this software for
@@ -27,24 +26,26 @@
#include "StringUtil.h"
#include "Test.h"
+
+
using namespace scsl;
static void
TestTrimming(std::string line, std::string lExpected, std::string rExpected, std::string expected)
{
- std::string result;
- std::string message;
+ std::string result;
+ std::string message;
- result = U::S::TrimLeadingWhitespaceDup(line);
+ result = U::S::TrimLeadingWhitespaceDup(line);
message = "TrimLeadingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == lExpected, message);
- result = U::S::TrimTrailingWhitespaceDup(line);
+ result = U::S::TrimTrailingWhitespaceDup(line);
message = "TrimTrailingDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == rExpected, message);
- result = U::S::TrimWhitespaceDup(line);
+ result = U::S::TrimWhitespaceDup(line);
message = "TrimDup(\"" + line + "\"): '" + result + "'";
TestAssert(result == expected, message);
@@ -68,7 +69,7 @@ TestTrimming(std::string line, std::string lExpected, std::string rExpected, std
static std::string
vec2string(std::vector v)
{
- std::stringstream ss;
+ std::stringstream ss;
ss << "(";
ss << v.size();
@@ -76,7 +77,7 @@ vec2string(std::vector v)
ss << "{";
for (size_t i = 0; i < v.size(); i++) {
- if (i > 0) ss << ", ";
+ if (i > 0) { ss << ", "; }
ss << v[i];
}
@@ -100,6 +101,36 @@ TestSplit(std::string line, std::string delim, size_t maxCount, std::vector expected{
+ "A much longer",
+ "line, something",
+ "that can be",
+ "tested with",
+ "WrapText. Does",
+ "it handle",
+ "puncuation? I",
+ "hope so.",
+ };
+
+ auto wrapped = U::S::WrapText(testLine, 16);
+ TestAssert(wrapped.size() == expected.size(),
+ U::S::VectorToString(wrapped) + " != " + U::S::VectorToString(expected));
+
+ for (size_t i = 0; i < wrapped.size(); i++) {
+ TestAssert(wrapped[i] == expected[i],
+ "\"" + wrapped[i] + "\" != \"" + expected[i] + "\"");
+ }
+
+ U::S::WriteTabIndented(std::cout, wrapped, 4, true);
+}
+
+
int
main()
{
@@ -116,4 +147,6 @@ main()
std::vector{"abc:def:ghij:klm"});
TestSplit("abc::def:ghi", ":", 0,
std::vector{"abc", "", "def", "ghi"});
+
+ TestWrapping();
}
\ No newline at end of file
diff --git a/tlvTest.cc b/tlvTest.cc
index 36782ba..f274ca1 100644
--- a/tlvTest.cc
+++ b/tlvTest.cc
@@ -48,13 +48,16 @@ tlvTestSuite(Arena &backend)
assert(cursor != nullptr);
assert(cmpRecord(rec3, rec4));
+ std::cout << "\tSetRecord 1\n";
TLV::SetRecord(rec4, 3, TEST_STRLEN3, TEST_STR3);
assert(TLV::WriteToMemory(backend, nullptr, rec4));
+ std::cout << "FindTag 3\n";
rec4.Tag = 2;
cursor = TLV::FindTag(backend, nullptr, rec4);
assert(cursor != nullptr);
+ std::cout << "DeleteRecord\n";
TLV::DeleteRecord(backend, cursor);
assert(cursor[0] == 3);
}