Cleanup code and docs; add missing header.
- The source and header files should have standard comment headers. - Windows support has been removed, as I've decomissioned my Windows desktop in favour of a Linux desktop. - Commander.h wasn't being added to the install directory.
This commit is contained in:
parent
0fff669b40
commit
407ee1c85d
|
@ -1,2 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="Python" name="Python facet">
|
||||
<configuration sdkName="Python 3.10 (scsl)" />
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
|
@ -1,4 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.10 (scsl)" />
|
||||
</component>
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
30
Arena.cc
30
Arena.cc
|
@ -1,19 +1,37 @@
|
|||
#include <cassert>
|
||||
///
|
||||
/// \file Arena.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-06
|
||||
/// \brief Memory management using an arena.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#if defined(__posix__) || defined(__linux__) || defined(__APPLE__)
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PROT_RW (PROT_WRITE|PROT_READ)
|
||||
#elif defined(__WIN64__) || defined(__WIN32__) || defined(WIN32)
|
||||
#include "WinHelpers.h"
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
#endif
|
||||
|
||||
#include <ios>
|
||||
|
@ -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:
|
||||
|
|
26
Arena.h
26
Arena.h
|
@ -1,11 +1,26 @@
|
|||
///
|
||||
/// \file Arena.h
|
||||
/// \author K. Isom
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-06
|
||||
/// \brief Memory management using an arena.
|
||||
///
|
||||
/// Arena defines a memory management backend for pre-allocating memory.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <iostream>
|
||||
#include <sys/stat.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#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
|
||||
|
|
18
Buffer.cc
18
Buffer.cc
|
@ -2,14 +2,28 @@
|
|||
/// \file Buffer.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-09
|
||||
/// \brief Buffer implements basic line buffers.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cassert>
|
||||
#include <cstring>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "Buffer.h"
|
||||
|
||||
|
|
17
Buffer.h
17
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 <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <iostream>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
namespace scsl {
|
||||
|
|
|
@ -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" "$<$<CONFIG:RELEASE>:/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"
|
||||
"$<$<CONFIG:RELEASE>:-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"
|
||||
"$<$<CONFIG:RELEASE>:-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()
|
||||
|
|
22
Commander.cc
22
Commander.cc
|
@ -1,12 +1,30 @@
|
|||
///
|
||||
/// \file Commander.cc
|
||||
/// \author kyle
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-10
|
||||
/// \brief Subprogram tooling.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <iostream>
|
||||
|
||||
#include "Commander.h"
|
||||
|
||||
|
||||
namespace scsl {
|
||||
|
||||
|
||||
|
@ -57,4 +75,4 @@ Commander::Run(std::string command, int argc, char **argv)
|
|||
}
|
||||
|
||||
|
||||
} // scsl
|
||||
} // namespace scsl
|
22
Commander.h
22
Commander.h
|
@ -12,9 +12,24 @@
|
|||
/// $ some_tool subcommand args...
|
||||
/// ```
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <map>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -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<bool(int, char **)> CommanderFunc;
|
||||
using CommanderFunc = std::function<bool (int, char **)>;
|
||||
|
||||
|
||||
/// Subcommands are the individual commands for the program. A Subcommand
|
||||
|
@ -104,7 +119,8 @@ private:
|
|||
std::map<std::string, Subcommand *> cmap;
|
||||
};
|
||||
|
||||
} // scsl
|
||||
|
||||
} // namespace scsl
|
||||
|
||||
|
||||
#endif //SCSL_COMMANDER_H
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
#include <cstring>
|
||||
///
|
||||
/// \file Dictionary.cc
|
||||
/// \author K.Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-05
|
||||
/// \brief Key-value store built on top of Arena and TLV.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "Dictionary.h"
|
||||
|
||||
#if defined(SCSL_DESKTOP_BUILD)
|
||||
|
|
25
Dictionary.h
25
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 <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cstdint>
|
||||
|
||||
#include "Arena.h"
|
||||
#include "TLV.h"
|
||||
|
||||
|
|
|
@ -1,6 +1,24 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
///
|
||||
/// \file Exceptions.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-10
|
||||
/// \brief Custom exceptions used in writing test programs.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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"
|
||||
|
||||
|
|
26
Exceptions.h
26
Exceptions.h
|
@ -1,7 +1,24 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
|
||||
///
|
||||
/// \file Exceptions.h
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-10
|
||||
/// \brief Custom exceptions for use in SCSL used in writing test programs.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <exception>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace scsl {
|
||||
|
||||
|
||||
|
|
146
Flag.cc
146
Flag.cc
|
@ -1,11 +1,9 @@
|
|||
///
|
||||
/// \file Flag.h
|
||||
/// \author kyle
|
||||
/// \created 2023-10-12
|
||||
/// \file Flag.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-12
|
||||
/// \brief Flag defines a command-line flag parser.
|
||||
///
|
||||
/// \section COPYRIGHT
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
|
@ -23,9 +21,7 @@
|
|||
///
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
|
@ -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<unsigned int>(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<size_t>(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;
|
||||
|
|
281
Flag.h
281
Flag.h
|
@ -1,11 +1,9 @@
|
|||
///
|
||||
/// \file Flag.h
|
||||
/// \author kyle
|
||||
/// \created 2023-10-12
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-12
|
||||
/// \brief Flag declares a command-line flag parser.
|
||||
///
|
||||
/// \section COPYRIGHT
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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<std::string> 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);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
|
||||
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.
|
75
Makefile
75
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) $<
|
||||
|
||||
|
|
|
@ -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 <kyle@imap.cc>
|
||||
|
||||
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.
|
||||
|
124
StringUtil.cc
124
StringUtil.cc
|
@ -1,3 +1,26 @@
|
|||
///
|
||||
/// \file StringUtil.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-12
|
||||
/// \brief Utilities for working with strings.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
@ -12,22 +35,21 @@ namespace U {
|
|||
namespace S {
|
||||
|
||||
|
||||
/*
|
||||
std::vector<std::string>
|
||||
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<std::string>
|
||||
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<std::string>
|
||||
WrapText(std::string line, size_t lineLength)
|
||||
{
|
||||
std::vector<std::string> 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<std::string> 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<std::string> &svec)
|
||||
{
|
||||
|
@ -141,7 +211,7 @@ VectorToString(std::ostream &os, const std::vector<std::string> &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<std::string> &svec)
|
|||
std::string
|
||||
VectorToString(const std::vector<std::string> &svec)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::stringstream ss;
|
||||
|
||||
VectorToString(ss, svec);
|
||||
return ss.str();
|
||||
|
|
42
StringUtil.h
42
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 <kyle@imap.cc>
|
||||
/// \date 2023-10-14
|
||||
/// \brief Utilities for working with strings.
|
||||
///
|
||||
/// \section COPYRIGHT
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
|
@ -85,17 +84,44 @@ std::vector<std::string> 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<std::string> SplitN(std::string, std::string delimiter, size_t maxCount=0);
|
||||
|
||||
//std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> &svec);
|
||||
|
||||
/// Return a string represention of a string vector in the form
|
||||
/// [size]{"foo", "bar", ...}.
|
||||
std::string VectorToString(const std::vector<std::string> &svec);
|
||||
|
||||
|
||||
|
|
36
TLV.cc
36
TLV.cc
|
@ -1,9 +1,35 @@
|
|||
///
|
||||
/// \file TLV.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-06
|
||||
/// \brief Tag-Length-Value records built on Arena.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
|
|
3
TLV.h
3
TLV.h
|
@ -14,8 +14,8 @@
|
|||
#ifndef KIMODEM_TLV_H
|
||||
#define KIMODEM_TLV_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include "Arena.h"
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
|||
namespace scsl {
|
||||
namespace TLV {
|
||||
|
||||
|
||||
#ifndef TLV_MAX_LEN
|
||||
static constexpr size_t TLV_MAX_LEN = 253;
|
||||
#endif
|
||||
|
|
25
Test.cc
25
Test.cc
|
@ -1,11 +1,28 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-09.
|
||||
//
|
||||
///
|
||||
/// \file Test.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-09
|
||||
/// \brief Tooling to assist in building test programs..
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
|
|
19
Test.h
19
Test.h
|
@ -2,11 +2,28 @@
|
|||
/// \file Test.h
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-09
|
||||
/// \brief Test.h implements basic testing tools.
|
||||
/// \brief Tooling to assist in building test programs..
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <string>
|
||||
|
||||
|
||||
|
|
142
WinHelpers.cc
142
WinHelpers.cc
|
@ -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
|
39
WinHelpers.h
39
WinHelpers.h
|
@ -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 <Windows.h>
|
||||
#include <winbase.h>
|
||||
#include <fileapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
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
|
|
@ -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
|
|
@ -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)
|
||||
|
10
flagTest.cc
10
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;
|
||||
}
|
25
phonebook.cc
25
phonebook.cc
|
@ -1,6 +1,24 @@
|
|||
//
|
||||
// Created by kyle on 2023-10-10.
|
||||
//
|
||||
///
|
||||
/// \file phonebook.cc
|
||||
/// \author K. Isom <kyle@imap.cc>
|
||||
/// \date 2023-10-10
|
||||
/// \brief Commandline tools for interacting with dictionary data file.
|
||||
///
|
||||
/// Copyright 2023 K. Isom <kyle@imap.cc>
|
||||
///
|
||||
/// 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 <iostream>
|
||||
#include <string>
|
||||
|
@ -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";
|
||||
|
|
22
scsl.h
22
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 <kyle@imap.cc>
|
||||
///
|
||||
/// Permission to use, copy, modify, and/or distribute this software for
|
||||
|
@ -25,12 +28,15 @@
|
|||
#define SCSL_SCSL_H
|
||||
|
||||
|
||||
#include <klib/Arena.h>
|
||||
#include <klib/Buffer.h>
|
||||
#include <klib/Dictionary.h>
|
||||
#include <klib/Exceptions.h>
|
||||
#include <klib/TLV.h>
|
||||
#include <klib/Test.h>
|
||||
#include <scsl/Arena.h>
|
||||
#include <scsl/Buffer.h>
|
||||
#include <scsl/Commander.h>
|
||||
#include <scsl/Dictionary.h>
|
||||
#include <scsl/Exceptions.h>
|
||||
#include <scsl/Flag.h>
|
||||
#include <scsl/StringUtil.h>
|
||||
#include <scsl/TLV.h>
|
||||
#include <scsl/Test.h>
|
||||
|
||||
|
||||
/// scsl is the top-level namespace containing all the code in this library.
|
||||
|
|
|
@ -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 <kyle@imap.cc>
|
||||
///
|
||||
/// 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<std::string> v)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "(";
|
||||
ss << v.size();
|
||||
|
@ -76,7 +77,7 @@ vec2string(std::vector<std::string> 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<std:
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
TestWrapping()
|
||||
{
|
||||
std::string testLine = "A much longer line, something that can be tested with WrapText. ";
|
||||
testLine += "Does it handle puncuation? I hope so.";
|
||||
|
||||
std::vector<std::string> 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<std::string>{"abc:def:ghij:klm"});
|
||||
TestSplit("abc::def:ghi", ":", 0,
|
||||
std::vector<std::string>{"abc", "", "def", "ghi"});
|
||||
|
||||
TestWrapping();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue