Add C++ to editorconfig & update formatting. No functional changes.

This commit is contained in:
Caelan Sayler
2021-09-01 16:03:27 +01:00
parent b9ab4a9336
commit 300f06cc82
23 changed files with 4060 additions and 3986 deletions

View File

@@ -123,3 +123,72 @@ insert_final_newline=false
[*.vb]
# Modifier preferences
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion
[*.{c++,cc,cpp,cppm,cxx,h,h++,hh,hpp,hxx,inl,ipp,ixx,tlh,tli}]
# Visual C++ Code Style settings
cpp_generate_documentation_comments = xml
# Visual C++ Formatting settings
indent_style = space
indent_size = 4
cpp_indent_braces = false
cpp_indent_multi_line_relative_to = innermost_parenthesis
cpp_indent_within_parentheses = indent
cpp_indent_preserve_within_parentheses = true
cpp_indent_case_contents = true
cpp_indent_case_labels = false
cpp_indent_case_contents_when_block = false
cpp_indent_lambda_braces_when_parameter = true
cpp_indent_goto_labels = one_left
cpp_indent_preprocessor = leftmost_column
cpp_indent_access_specifiers = false
cpp_indent_namespace_contents = true
cpp_indent_preserve_comments = false
cpp_new_line_before_open_brace_namespace = new_line
cpp_new_line_before_open_brace_type = new_line
cpp_new_line_before_open_brace_function = new_line
cpp_new_line_before_open_brace_block = same_line
cpp_new_line_before_open_brace_lambda = ignore
cpp_new_line_scope_braces_on_separate_lines = false
cpp_new_line_close_brace_same_line_empty_type = false
cpp_new_line_close_brace_same_line_empty_function = false
cpp_new_line_before_catch = true
cpp_new_line_before_else = true
cpp_new_line_before_while_in_do_while = false
cpp_space_before_function_open_parenthesis = remove
cpp_space_within_parameter_list_parentheses = false
cpp_space_between_empty_parameter_list_parentheses = false
cpp_space_after_keywords_in_control_flow_statements = true
cpp_space_within_control_flow_statement_parentheses = false
cpp_space_before_lambda_open_parenthesis = false
cpp_space_within_cast_parentheses = false
cpp_space_after_cast_close_parenthesis = false
cpp_space_within_expression_parentheses = false
cpp_space_before_block_open_brace = true
cpp_space_between_empty_braces = false
cpp_space_before_initializer_list_open_brace = false
cpp_space_within_initializer_list_braces = true
cpp_space_preserve_in_initializer_list = true
cpp_space_before_open_square_bracket = false
cpp_space_within_square_brackets = false
cpp_space_before_empty_square_brackets = false
cpp_space_between_empty_square_brackets = false
cpp_space_group_square_brackets = true
cpp_space_within_lambda_brackets = false
cpp_space_between_empty_lambda_brackets = false
cpp_space_before_comma = false
cpp_space_after_comma = true
cpp_space_remove_around_member_operators = true
cpp_space_before_inheritance_colon = true
cpp_space_before_constructor_colon = true
cpp_space_remove_before_semicolon = true
cpp_space_after_semicolon = false
cpp_space_remove_around_unary_operator = true
cpp_space_around_binary_operator = insert
cpp_space_around_assignment_operator = insert
cpp_space_pointer_reference_alignment = left
cpp_space_around_ternary_operator = insert
cpp_wrap_preserve_blocks = one_liners

View File

@@ -10,22 +10,18 @@ class ATL_NO_VTABLE CDownloadProgressCallback :
{
public:
CDownloadProgressCallback()
{
}
{}
DECLARE_NOT_AGGREGATABLE(CDownloadProgressCallback)
BEGIN_COM_MAP(CDownloadProgressCallback)
COM_INTERFACE_ENTRY(IBindStatusCallback)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct() { return S_OK; }
void FinalRelease()
{
}
{}
void SetProgressDialog(IProgressDialog* pd)
{
@@ -98,7 +94,8 @@ HRESULT CFxHelper::InstallDotnet(const RUNTIMEINFO* runtime, bool isQuiet)
if (dwTempPathResult == 0) {
hr = AtlHresultFromLastError();
goto out;
} else if (dwTempPathResult > _MAX_PATH) {
}
else if (dwTempPathResult > _MAX_PATH) {
hr = DISP_E_BUFFERTOOSMALL;
goto out;
}
@@ -121,7 +118,8 @@ HRESULT CFxHelper::InstallDotnet(const RUNTIMEINFO* runtime, bool isQuiet)
hr = E_FAIL;
goto out;
}
} else {
}
else {
if (wcscpy_s(pLastDot, _countof(szFinalTempFileName) - (pLastDot - szFinalTempFileName), L".exe") != 0) {
hr = E_FAIL;
goto out;

View File

@@ -3,10 +3,12 @@
class CFxHelper
{
public:
static HRESULT InstallDotnet(const RUNTIMEINFO* runtime, bool isQuiet);
static HRESULT HandleRebootRequirement(bool isQuiet);
private:
static bool WriteRunOnceEntry();
static bool RebootSystem();
};

View File

@@ -17,27 +17,21 @@ IStream* LoadImageFromResource(const wchar_t* resid, const wchar_t* restype)
HINSTANCE hInst = GetModuleHandle(NULL);
HRSRC hrsrc = FindResourceW(hInst, resid, restype); // get the handle to the resource
if (hrsrc)
{
if (hrsrc) {
DWORD dwResourceSize = SizeofResource(hInst, hrsrc);
if (dwResourceSize > 0)
{
if (dwResourceSize > 0) {
HGLOBAL hGlobalResource = LoadResource(hInst, hrsrc); // load it
if (hGlobalResource)
{
if (hGlobalResource) {
void* imagebytes = LockResource(hGlobalResource); // get a pointer to the file bytes
// copy image bytes into a real hglobal memory handle
hGlobal = ::GlobalAlloc(GHND, dwResourceSize);
if (hGlobal)
{
if (hGlobal) {
void* pBuffer = ::GlobalLock(hGlobal);
if (pBuffer)
{
if (pBuffer) {
memcpy(pBuffer, imagebytes, dwResourceSize);
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pStream);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(hr)) {
// pStream now owns the global handle and will invoke GlobalFree on release
hGlobal = nullptr;
}
@@ -47,8 +41,7 @@ IStream* LoadImageFromResource(const wchar_t* resid, const wchar_t* restype)
}
}
if (hGlobal)
{
if (hGlobal) {
GlobalFree(hGlobal);
hGlobal = nullptr;
}
@@ -61,8 +54,7 @@ ImageEx::ImageEx(const wchar_t* resid, const wchar_t* restype)
Initialize();
auto stream = LoadImageFromResource(resid, restype);
if (stream)
{
if (stream) {
nativeImage = NULL;
lastResult = DllExports::GdipLoadImageFromStreamICM(stream, &nativeImage);
m_bIsInitialized = true;
@@ -78,27 +70,22 @@ ImageEx::~ImageEx()
bool ImageEx::InitAnimation(HWND hWnd, CPoint pt)
{
m_hWnd = hWnd;
m_pt = pt;
if (!m_bIsInitialized)
{
if (!m_bIsInitialized) {
TRACE(_T("GIF not initialized\n"));
return false;
};
if (IsAnimatedGIF())
{
if (m_hThread == NULL)
{
if (IsAnimatedGIF()) {
if (m_hThread == NULL) {
unsigned int nTID = 0;
m_hThread = (HANDLE)_beginthreadex(NULL, 0, _ThreadAnimationProc, this, CREATE_SUSPENDED, &nTID);
if (!m_hThread)
{
if (!m_hThread) {
TRACE(_T("Couldn't start a GIF animation thread\n"));
return true;
}
@@ -176,8 +163,7 @@ void ImageEx::ThreadAnimation()
m_nFramePosition = 0;
bool bExit = false;
while (bExit == false)
{
while (bExit == false) {
bExit = DrawFrameGIF();
}
}
@@ -192,8 +178,7 @@ bool ImageEx::DrawFrameGIF()
long hmHeight = GetHeight();
HDC hDC = GetDC(m_hWnd);
if (hDC)
{
if (hDC) {
Graphics graphics(hDC);
graphics.DrawImage(this, m_pt.x, m_pt.y, hmWidth, hmHeight);
ReleaseDC(m_hWnd, hDC);
@@ -214,15 +199,12 @@ void ImageEx::SetPause(bool bPause)
if (!IsAnimatedGIF())
return;
if (bPause && !m_bPause)
{
if (bPause && !m_bPause) {
::ResetEvent(m_hPause);
}
else
{
else {
if (m_bPause && !bPause)
{
if (m_bPause && !bPause) {
::SetEvent(m_hPause);
}
}
@@ -234,8 +216,7 @@ void ImageEx::SetPause(bool bPause)
void ImageEx::Destroy()
{
if (m_hThread)
{
if (m_hThread) {
// If pause un pause
SetPause(false);

View File

@@ -4,7 +4,8 @@
#include "resource.h"
#include <sddl.h>
bool directoryExists(wchar_t* path) {
bool directoryExists(wchar_t* path)
{
DWORD dwResult = GetFileAttributes(path);
if (dwResult != INVALID_FILE_ATTRIBUTES) {

View File

@@ -1,6 +1,8 @@
#pragma once
class MachineInstaller
{
public:
static bool ShouldSilentInstall();
};

View File

@@ -114,8 +114,7 @@ RUNTIMEINFO supported_runtimes[] =
const RUNTIMEINFO* GetRuntimeByName(wstring name)
{
for (int i = 0; i < NUM_RUNTIMES; i++)
{
for (int i = 0; i < NUM_RUNTIMES; i++) {
const RUNTIMEINFO* item = &supported_runtimes[i];
auto itemName = wstring(item->name);
@@ -150,7 +149,8 @@ bool IsFullNetFrameworkInstalled(DWORD requiredVersion)
}
// TODO this is extremely messy, it should certainly be re-written.
wstring exec(const char* cmd) {
wstring exec(const char* cmd)
{
char buffer[128];
string result = "";
FILE* pipe = _popen(cmd, "r");
@@ -187,12 +187,10 @@ bool IsDotNetCoreInstalled(wstring searchString)
bool IsRuntimeInstalled(const RUNTIMEINFO* runtime)
{
if (runtime->fxReleaseVersion > 0)
{
if (runtime->fxReleaseVersion > 0) {
return IsFullNetFrameworkInstalled(runtime->fxReleaseVersion);
}
else
{
else {
return IsDotNetCoreInstalled(wstring(runtime->dncRuntimeVersionName));
}
}
@@ -203,8 +201,7 @@ int ParseRuntimeString(std::wstring version, vector<const RUNTIMEINFO*>& runtime
int ret = S_OK;
wstring temp;
std::wstringstream wss(version);
while (std::getline(wss, temp, L','))
{
while (std::getline(wss, temp, L',')) {
const RUNTIMEINFO* rt = GetRuntimeByName(temp);
if (rt != nullptr)
runtimes.push_back(rt);

View File

@@ -45,28 +45,23 @@ void CSplashWnd::SetImage(const wchar_t* resid, const wchar_t* restype)
void CSplashWnd::Show()
{
if (m_hThread == NULL)
{
if (m_hThread == NULL) {
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
m_hThread = (HANDLE)_beginthreadex(NULL, 0, SplashThreadProc, static_cast<LPVOID>(this), 0, &m_ThreadId);
if (WaitForSingleObject(m_hEvent, 5000) == WAIT_TIMEOUT)
{
if (WaitForSingleObject(m_hEvent, 5000) == WAIT_TIMEOUT) {
OutputDebugString(L"Error starting SplashThread\n");
}
}
else
{
else {
PostThreadMessage(m_ThreadId, WM_ACTIVATE, WA_CLICKACTIVE, 0);
}
}
void CSplashWnd::Hide()
{
if (m_hThread)
{
if (m_hThread) {
PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);
if (WaitForSingleObject(m_hThread, 9000) == WAIT_TIMEOUT)
{
if (WaitForSingleObject(m_hThread, 9000) == WAIT_TIMEOUT) {
::TerminateThread(m_hThread, 2222);
}
CloseHandle(m_hThread);
@@ -101,8 +96,7 @@ unsigned int __stdcall CSplashWnd::SplashThreadProc(void* lpParameter)
wndcls.lpszClassName = L"SplashWnd";
wndcls.hIcon = LoadIcon(wndcls.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
if (!RegisterClass(&wndcls))
{
if (!RegisterClass(&wndcls)) {
if (GetLastError() != 0x00000582) // already registered)
{
OutputDebugString(L"Unable to register class SplashWnd\n");
@@ -118,13 +112,11 @@ unsigned int __stdcall CSplashWnd::SplashThreadProc(void* lpParameter)
::GetCursorPos(&point);
hMonitor = ::MonitorFromPoint(point, MONITOR_DEFAULTTONEAREST);
if (::GetMonitorInfo(hMonitor, &mi))
{
if (::GetMonitorInfo(hMonitor, &mi)) {
rcArea.left = (mi.rcMonitor.right + mi.rcMonitor.left - static_cast<long>(pThis->m_pImage->GetWidth())) / 2;
rcArea.top = (mi.rcMonitor.top + mi.rcMonitor.bottom - static_cast<long>(pThis->m_pImage->GetHeight())) / 2;
}
else
{
else {
SystemParametersInfo(SPI_GETWORKAREA, NULL, &rcArea, NULL);
rcArea.left = (rcArea.right + rcArea.left - pThis->m_pImage->GetWidth()) / 2;
rcArea.top = (rcArea.top + rcArea.bottom - pThis->m_pImage->GetHeight()) / 2;
@@ -141,8 +133,7 @@ unsigned int __stdcall CSplashWnd::SplashThreadProc(void* lpParameter)
wndcls.hInstance,
NULL);
if (!pThis->m_hSplashWnd)
{
if (!pThis->m_hSplashWnd) {
OutputDebugString(L"Unable to create SplashWnd\n");
return 0;
}
@@ -159,16 +150,13 @@ unsigned int __stdcall CSplashWnd::SplashThreadProc(void* lpParameter)
PeekMessage(&msg, NULL, 0, 0, 0); // invoke creating message queue
SetEvent(pThis->m_hEvent);
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
{
while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (msg.message == WM_QUIT) break;
if (bRet == -1)
{
if (bRet == -1) {
// handle the error and possibly exit
}
else
{
else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
@@ -181,24 +169,19 @@ unsigned int __stdcall CSplashWnd::SplashThreadProc(void* lpParameter)
LRESULT CALLBACK CSplashWnd::SplashWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CSplashWnd* pInstance = reinterpret_cast<CSplashWnd*>(GetWindowLongPtr(hwnd, GWL_USERDATA));
if (pInstance == NULL)
{
if (pInstance == NULL) {
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
switch (uMsg)
{
switch (uMsg) {
case WM_PAINT:
{
if (pInstance->m_pImage)
{
if (pInstance->m_pImage->IsAnimatedGIF())
{
if (pInstance->m_pImage) {
if (pInstance->m_pImage->IsAnimatedGIF()) {
// do nothing, the gif will be drawn by it's own thread.
}
else
{
else {
Gdiplus::Graphics gdip(hwnd);
gdip.DrawImage(pInstance->m_pImage, 0, 0, pInstance->m_pImage->GetWidth(), pInstance->m_pImage->GetHeight());
}
@@ -216,8 +199,7 @@ LRESULT CALLBACK CSplashWnd::SplashWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
case WM_MOUSEMOVE:
{
if (GetCapture() == hwnd)
{
if (GetCapture() == hwnd) {
RECT rcWnd;
GetWindowRect(hwnd, &rcWnd);

View File

@@ -36,7 +36,6 @@ public:
CSplashWnd(HWND hParent = NULL);
~CSplashWnd();
void SetImage(const wchar_t* resid, const wchar_t* restype);
void SetWindowName(const wchar_t* windowName);
void Show();
void Hide();

View File

@@ -15,7 +15,8 @@ void CUpdateRunner::DisplayErrorMessage(CString& errorMessage, wchar_t* logFile)
// TODO: Something about contacting support?
if (logFile == NULL) {
dlg.SetButtons(&buttons[1], 1, 1);
} else {
}
else {
dlg.SetButtons(buttons, 2, 1);
}

View File

@@ -11,4 +11,5 @@ public:
static bool DirectoryExists(wchar_t* szPath);
static bool DirectoryIsWritable(wchar_t* szPath);
static int ExtractUpdaterAndRun(wchar_t* lpCommandLine, bool useFallbackDir, std::function<void()>& callback);
};

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,8 @@ typedef DWORD ZRESULT;
// return codes from any of the zip functions. Listed later.
typedef struct
{ int index; // index of this file within the zip
{
int index; // index of this file within the zip
TCHAR name[MAX_PATH]; // filename within the zip
DWORD attr; // attributes, as in GetFileAttributes.
FILETIME atime, ctime, mtime;// access, create, modify filetimes

View File

@@ -61,15 +61,13 @@ int APIENTRY wWinMain(
// see if the requested framework(s) are supported and exit.
int chkFrameworkIdx = cmdLine.Find(L"--checkFramework");
if (chkFrameworkIdx >= 0) {
if (chkFrameworkIdx >= 0)
return VerifyRuntimeString(std::wstring(cmdLine).substr(chkFrameworkIdx + 17));
}
if (cmdLine.Find(L"--checkInstall") >= 0) {
// If we're already installed, exit as fast as possible
if (!MachineInstaller::ShouldSilentInstall()) {
if (!MachineInstaller::ShouldSilentInstall())
return 0;
}
// Make sure update.exe gets silent
wcscat(lpCmdLine, L" --silent");
@@ -107,10 +105,8 @@ int APIENTRY wWinMain(
bool rebootRequired = false;
// check all required runtimes against the current operating system version
for (auto rt : runtimes)
{
if (!IsRuntimeSupported(rt))
{
for (auto rt : runtimes) {
if (!IsRuntimeSupported(rt)) {
// Explain this as nicely as possible and give up.
MessageBox(0L, L"This program cannot run on this computer; it requires a later version of Windows.", L"Incompatible Operating System", 0);
exitCode = E_FAIL;
@@ -119,25 +115,20 @@ int APIENTRY wWinMain(
}
// install any missing runtimes
for (auto rt : runtimes)
{
if (!IsRuntimeInstalled(rt))
{
for (auto rt : runtimes) {
if (!IsRuntimeInstalled(rt)) {
HRESULT hr = CFxHelper::InstallDotnet(rt, isQuiet);
if (hr == ERROR_SUCCESS_REBOOT_REQUIRED)
{
if (hr == ERROR_SUCCESS_REBOOT_REQUIRED) {
// we will reboot after installing all required runtimes.
rebootRequired = true;
}
else if (FAILED(hr))
{
else if (FAILED(hr)) {
exitCode = hr; // #yolo
CUpdateRunner::DisplayErrorMessage(CString(L"Failed to install .NET, you can try installing it manually."), NULL);
goto out;
}
// S_FALSE isn't failure, but we still shouldn't try to install
else if (hr != S_OK)
{
else if (hr != S_OK) {
exitCode = 0;
goto out;
}
@@ -145,8 +136,7 @@ int APIENTRY wWinMain(
}
// if any runtimes indicated a reboot is required, let's do that now
if (rebootRequired)
{
if (rebootRequired) {
exitCode = CFxHelper::HandleRebootRequirement(isQuiet);
goto out;
}

View File

@@ -31,12 +31,15 @@ SOFTWARE.
using namespace std;
namespace version {
namespace version
{
namespace {
namespace
{
// Compare normal version identifiers.
int compare_normal(const Version_data& l, const Version_data& r) {
int compare_normal(const Version_data& l, const Version_data& r)
{
if (l.major > r.major) return 1;
if (l.major < r.major) return -1;
if (l.minor > r.minor) return 1;
@@ -47,17 +50,20 @@ namespace version {
}
// Compare alphanumeric prerelease identifiers.
inline int cmp_alnum_prerel_ids(const string& l, const string& r) {
inline int cmp_alnum_prerel_ids(const string& l, const string& r)
{
auto cmp = l.compare(r);
if (cmp == 0) {
return cmp;
} else {
}
else {
return cmp > 0 ? 1 : -1;
}
}
// Compare numeric prerelease identifiers.
inline int cmp_num_prerel_ids(const string& l, const string& r) {
inline int cmp_num_prerel_ids(const string& l, const string& r)
{
long long li = stoll(l);
long long ri = stoll(r);
if (li == ri) return 0;
@@ -74,19 +80,22 @@ namespace version {
};
// Compare prerelease identifiers based on their types.
inline int compare_prerel_identifiers(const Prerelease_identifier& l, const Prerelease_identifier& r) {
inline int compare_prerel_identifiers(const Prerelease_identifier& l, const Prerelease_identifier& r)
{
auto cmp = comparators.at({ l.second, r.second });
return cmp(l.first, r.first);
}
inline int cmp_rel_prerel(const Prerelease_identifiers& l, const Prerelease_identifiers& r) {
inline int cmp_rel_prerel(const Prerelease_identifiers& l, const Prerelease_identifiers& r)
{
if (l.empty() && !r.empty()) return 1;
if (r.empty() && !l.empty()) return -1;
return 0;
}
}
int Semver200_comparator::compare(const Version_data& l, const Version_data& r) const {
int Semver200_comparator::compare(const Version_data& l, const Version_data& r) const
{
// Compare normal version components.
int cmp = compare_normal(l, r);
if (cmp != 0) return cmp;

View File

@@ -35,10 +35,13 @@ SOFTWARE.
using namespace std;
namespace version {
namespace version
{
namespace {
enum class Parser_state {
namespace
{
enum class Parser_state
{
major, minor, patch, prerelease, build
};
@@ -56,7 +59,8 @@ namespace version {
{ '0', '9' },{ 'A','Z' },{ 'a','z' },{ '-','-' }
};
inline Transition mkx(const char c, Parser_state p, State_transition_hook pth) {
inline Transition mkx(const char c, Parser_state p, State_transition_hook pth)
{
return make_tuple(c, p, pth);
}
@@ -69,7 +73,8 @@ namespace version {
where whole tokens are validated.
*/
inline void process_char(const char c, Parser_state& cstate, Parser_state& pstate,
const Transitions& transitions, string& target, Validator validate) {
const Transitions& transitions, string& target, Validator validate)
{
for (const auto& transition : transitions) {
if (c == get<0>(transition)) {
if (get<2>(transition)) get<2>(transition)(target);
@@ -83,13 +88,15 @@ namespace version {
}
/// Validate normal (major, minor, patch) version components.
inline void normal_version_validator(const string& tgt, const char c) {
inline void normal_version_validator(const string& tgt, const char c)
{
if (c < '0' || c > '9') throw Parse_error("invalid character encountered: " + string(1, c));
if (tgt.compare(0, 1, "0") == 0) throw Parse_error("leading 0 not allowed");
}
/// Validate that prerelease and build version identifiers are comprised of allowed chars only.
inline void prerelease_version_validator(const string&, const char c) {
inline void prerelease_version_validator(const string&, const char c)
{
bool res = false;
for (const auto& r : allowed_prerel_id_chars) {
res |= (c >= r.first && c <= r.second);
@@ -98,16 +105,19 @@ namespace version {
throw Parse_error("invalid character encountered: " + string(1, c));
}
inline bool is_identifier_numeric(const string& id) {
inline bool is_identifier_numeric(const string& id)
{
return id.find_first_not_of("0123456789") == string::npos;
}
inline bool check_for_leading_0(const string& str) {
inline bool check_for_leading_0(const string& str)
{
return str.length() > 1 && str[0] == '0';
}
/// Validate every individual prerelease identifier, determine it's type and add it to collection.
void prerelease_hook_impl(string& id, Prerelease_identifiers& prerelease) {
void prerelease_hook_impl(string& id, Prerelease_identifiers& prerelease)
{
if (id.empty()) throw Parse_error("version identifier cannot be empty");
Id_type t = Id_type::alnum;
if (is_identifier_numeric(id)) {
@@ -122,7 +132,8 @@ namespace version {
/// Validate every individual build identifier and add it to collection.
void build_hook_impl(string& id, Parser_state& pstate, Build_identifiers& build,
std::string& prerelease_id, Prerelease_identifiers& prerelease) {
std::string& prerelease_id, Prerelease_identifiers& prerelease)
{
// process last token left from parsing prerelease data
if (pstate == Parser_state::prerelease) prerelease_hook_impl(prerelease_id, prerelease);
if (id.empty()) throw Parse_error("version identifier cannot be empty");
@@ -138,7 +149,8 @@ namespace version {
string is consumed and is either added to current token or triggers state transition. Hooks can be
injected into state transitions for validation/customization purposes.
*/
Version_data Semver200_parser::parse(const string& s) const {
Version_data Semver200_parser::parse(const string& s) const
{
string major;
string minor;
string patch;
@@ -197,13 +209,15 @@ namespace version {
// triggered for it.
if (cstate == Parser_state::prerelease) {
prerelease_hook(prerelease_id);
} else if (cstate == Parser_state::build) {
}
else if (cstate == Parser_state::build) {
build_hook(build_id);
}
try {
return Version_data{ stoi(major), stoi(minor), stoi(patch), prerelease, build };
} catch (invalid_argument& ex) {
}
catch (invalid_argument& ex) {
throw Parse_error(ex.what());
}
}

View File

@@ -26,26 +26,32 @@ SOFTWARE.
#include "version.h"
namespace version {
namespace version
{
/// Parse string into Version_data structure according to semantic versioning 2.0.0 rules.
struct Semver200_parser {
struct Semver200_parser
{
Version_data parse(const std::string&) const;
};
/// Compare Version_data to another using semantic versioning 2.0.0 rules.
struct Semver200_comparator {
struct Semver200_comparator
{
int compare(const Version_data&, const Version_data&) const;
};
/// Concrete version class that binds all semver 2.0.0 functionality together.
class Semver200_version : public Basic_version<Semver200_parser, Semver200_comparator> {
class Semver200_version : public Basic_version<Semver200_parser, Semver200_comparator>
{
public:
Semver200_version()
: Basic_version{ Semver200_parser(), Semver200_comparator() } {}
: Basic_version{ Semver200_parser(), Semver200_comparator() }
{}
Semver200_version(const std::string& v)
: Basic_version{ v, Semver200_parser(), Semver200_comparator() } {}
: Basic_version{ v, Semver200_parser(), Semver200_comparator() }
{}
};
}

View File

@@ -28,10 +28,12 @@ SOFTWARE.
#include <string>
#include <vector>
namespace version {
namespace version
{
/// Any error in parsing or validation of version string will result in Parse_error exception being thrown.
class Parse_error : public std::runtime_error {
class Parse_error : public std::runtime_error
{
using std::runtime_error::runtime_error;
};
@@ -40,7 +42,8 @@ namespace version {
Type of identifier affects comparison: alphanumeric identifiers are compared as ASCII strings, while
numeric identifiers are compared as numbers.
*/
enum class Id_type {
enum class Id_type
{
alnum, ///< Identifier is alphanumerical
num ///< Identifier is numeric
};
@@ -63,7 +66,8 @@ namespace version {
using Build_identifiers = std::vector<Build_identifier>;
/// Description of version broken into parts, as per semantic versioning specification.
struct Version_data {
struct Version_data
{
int major; ///< Major version, change only on incompatible API modifications.
int minor; ///< Minor version, change on backwards-compatible API modifications.
int patch; ///< Patch version, change only on bugfixes.
@@ -122,7 +126,8 @@ namespace version {
Comparator objects.
*/
template<typename Parser, typename Comparator>
class Basic_version {
class Basic_version
{
public:
/// Construct Basic_version object using Parser object to parse default ("0.0.0") version string and Comparator for comparison.
Basic_version(Parser, Comparator);

View File

@@ -11,8 +11,10 @@
#include <unordered_map>
#include <vector>
namespace flags {
namespace detail {
namespace flags
{
namespace detail
{
using argument_map =
std::unordered_map<std::wstring_view, std::optional<std::wstring_view>>;
@@ -21,8 +23,10 @@ namespace flags {
// * If the token does not begin with a -, it will be considered a value for the
// previous option. If there was no previous option, it will be considered a
// positional argument.
struct parser {
parser(const int argc, wchar_t** argv) {
struct parser
{
parser(const int argc, wchar_t** argv)
{
for (int i = 1; i < argc; ++i) {
churn(argv[i]);
}
@@ -32,22 +36,26 @@ namespace flags {
parser& operator=(const parser&) = delete;
const argument_map& options() const { return options_; }
const std::vector<std::wstring_view>& positional_arguments() const {
const std::vector<std::wstring_view>& positional_arguments() const
{
return positional_arguments_;
}
private:
// Advance the state machine for the current token.
void churn(const std::wstring_view& item) {
void churn(const std::wstring_view& item)
{
item.at(0) == '-' ? on_option(item) : on_value(item);
}
// Consumes the current option if there is one.
void flush() {
void flush()
{
if (current_option_) on_value();
}
void on_option(const std::wstring_view& option) {
void on_option(const std::wstring_view& option)
{
// Consume the current_option and reassign it to the new option while
// removing all leading dashes.
flush();
@@ -64,7 +72,8 @@ namespace flags {
}
}
void on_value(const std::optional<std::wstring_view>& value = std::nullopt) {
void on_value(const std::optional<std::wstring_view>& value = std::nullopt)
{
// If there's not an option preceding the value, it's a positional argument.
if (!current_option_) {
if (value) positional_arguments_.emplace_back(*value);
@@ -82,7 +91,8 @@ namespace flags {
// If a key exists, return an optional populated with its value.
inline std::optional<std::wstring_view> get_value(
const argument_map& options, const std::wstring_view& option) {
const argument_map& options, const std::wstring_view& option)
{
if (const auto it = options.find(option); it != options.end()) {
return it->second;
}
@@ -94,7 +104,8 @@ namespace flags {
// nullopt.
template <class T>
std::optional<T> get(const argument_map& options,
const std::wstring_view& option) {
const std::wstring_view& option)
{
if (const auto view = get_value(options, option)) {
if (T value; std::istringstream(std::wstring(*view)) >> value) return value;
}
@@ -104,13 +115,15 @@ namespace flags {
// Since the values are already stored as strings, there's no need to use `>>`.
template <>
inline std::optional<std::wstring_view> get(const argument_map& options,
const std::wstring_view& option) {
const std::wstring_view& option)
{
return get_value(options, option);
}
template <>
inline std::optional<std::wstring> get(const argument_map& options,
const std::wstring_view& option) {
const std::wstring_view& option)
{
if (const auto view = get<std::wstring_view>(options, option)) {
return std::wstring(*view);
}
@@ -123,7 +136,8 @@ namespace flags {
constexpr std::array<const wchar_t*, 5> falsities{ {L"0", L"n", L"no", L"f", L"false"} };
template <>
inline std::optional<bool> get(const argument_map& options,
const std::wstring_view& option) {
const std::wstring_view& option)
{
if (const auto value = get_value(options, option)) {
return std::none_of(falsities.begin(), falsities.end(),
[&value](auto falsity) { return *value == falsity; });
@@ -137,7 +151,8 @@ namespace flags {
// nullopt.
template <class T>
std::optional<T> get(const std::vector<std::wstring_view>& positional_arguments,
size_t positional_index) {
size_t positional_index)
{
if (positional_index < positional_arguments.size()) {
if (T value; std::istringstream(
std::wstring(positional_arguments[positional_index])) >>
@@ -151,7 +166,8 @@ namespace flags {
template <>
inline std::optional<std::wstring_view> get(
const std::vector<std::wstring_view>& positional_arguments,
size_t positional_index) {
size_t positional_index)
{
if (positional_index < positional_arguments.size()) {
return positional_arguments[positional_index];
}
@@ -161,7 +177,8 @@ namespace flags {
template <>
inline std::optional<std::wstring> get(
const std::vector<std::wstring_view>& positional_arguments,
size_t positional_index) {
size_t positional_index)
{
if (positional_index < positional_arguments.size()) {
return std::wstring(positional_arguments[positional_index]);
}
@@ -169,30 +186,36 @@ namespace flags {
}
} // namespace detail
struct args {
struct args
{
args(const int argc, wchar_t** argv) : parser_(argc, argv) {}
template <class T>
std::optional<T> get(const std::wstring_view& option) const {
std::optional<T> get(const std::wstring_view& option) const
{
return detail::get<T>(parser_.options(), option);
}
template <class T>
T get(const std::wstring_view& option, T&& default_value) const {
T get(const std::wstring_view& option, T&& default_value) const
{
return get<T>(option).value_or(default_value);
}
template <class T>
std::optional<T> get(size_t positional_index) const {
std::optional<T> get(size_t positional_index) const
{
return detail::get<T>(parser_.positional_arguments(), positional_index);
}
template <class T>
T get(size_t positional_index, T&& default_value) const {
T get(size_t positional_index, T&& default_value) const
{
return get<T>(positional_index).value_or(default_value);
}
const std::vector<std::wstring_view>& positional() const {
const std::vector<std::wstring_view>& positional() const
{
return parser_.positional_arguments();
}