refactor: rewrite the plugin in rust

This commit is contained in:
amrbashir
2023-01-02 14:23:16 +02:00
parent 3b26304c28
commit b547268fa6
20 changed files with 367 additions and 1584 deletions

2
.cargo/config.toml Normal file
View File

@@ -0,0 +1,2 @@
[build]
target = "i686-pc-windows-msvc"

8
.gitignore vendored
View File

@@ -1,6 +1,4 @@
Release/ /target
Debug/ /Cargo.lock
.vscode/
.vs/
*.user
*.exe *.exe
.vscode/

15
Cargo.toml Normal file
View File

@@ -0,0 +1,15 @@
[package]
name = "nsis-semvercompare"
version = "0.0.0"
edition = "2021"
license = "MIT OR Apache-2.0"
[lib]
crate-type = ["cdylib"]
[dependencies]
semver = "1.0.16"
[dependencies.windows-sys]
version = "0.42.0"
features = ["Win32_System_Memory", "Win32_Foundation", "Win32_Globalization"]

177
LICENSE_APACHE-2.0 Normal file
View File

@@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2017 Alexei Sitnikov Copyright (c) 2019 - 2022 Tauri Programme within The Commons Conservancy
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,46 +0,0 @@
#include <stdio.h>
#include <strsafe.h>
#include <tchar.h>
#include <windows.h>
#include <optional>
#include <string>
#include "include\nsis\pluginapi.h"
#include "include\semver.hpp"
#define NSIS_MAX_STRLEN 1024
extern "C" void __declspec(dllexport) SemverCompare(HWND hwndParent,
int string_size,
TCHAR* variables,
stack_t** stacktop,
extra_parameters* extra) {
EXDLL_INIT();
TCHAR arg1[NSIS_MAX_STRLEN];
if (popstringn(arg1, NSIS_MAX_STRLEN))
return;
TCHAR arg2[NSIS_MAX_STRLEN];
if (popstringn(arg2, NSIS_MAX_STRLEN))
return;
std::wstring ver1w(arg1);
std::wstring ver2w(arg2);
std::string ver1(ver1w.begin(), ver1w.end());
std::string ver2(ver2w.begin(), ver2w.end());
std::optional<semver::version> v1 = semver::from_string_noexcept(ver1);
std::optional<semver::version> v2 = semver::from_string_noexcept(ver2);
if (v1.has_value() && !v2.has_value()) {
pushint(1);
} else if (!v1.has_value() && v2.has_value()) {
pushint(-1);
} else if (!v1.has_value() && !v2.has_value()) {
pushint(0);
} else {
pushint(v1.value().compare(v2.value()));
}
}

View File

@@ -1,36 +0,0 @@
Name "SemverCompare"
OutFile "SemverCompare.exe"
ShowInstDetails show
!addplugindir "Debug"
!addplugindir "Release"
Section "nsSemverCompare"
SemverCompare::SemverCompare "1.2.1" "1.2.0"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.0" "1.2.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.1" "1.2.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.1-alpha.1" "1.2.1-beta.5"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.1-rc.1" "1.2.1-beta.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.1-alpha.1" "1.2.1-alpha.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2qe2.1-alpha.1" "1.2.1-alpha.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.1-alpha.1" "-q1.2.1-alpha.1"
Pop $1
DetailPrint $1
SemverCompare::SemverCompare "1.2.saf1-alpha.1" "-q1.2.1-alpha.1"
Pop $1
DetailPrint $1
SectionEnd

View File

@@ -1,20 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SemverCompare", "SemverCompare.vcxproj", "{EE997742-B1B4-4FA0-A46E-E8F2614D457B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Debug|Win32.ActiveCfg = Debug|Win32
{EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Debug|Win32.Build.0 = Debug|Win32
{EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Release|Win32.ActiveCfg = Release|Win32
{EE997742-B1B4-4FA0-A46E-E8F2614D457B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -1,101 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{EE997742-B1B4-4FA0-A46E-E8F2614D457B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>SemverCompare</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v143</PlatformToolset>
<UseOfMfc>false</UseOfMfc>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SemverCompare_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;include/nsis/pluginapi.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SemverCompare_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<LanguageStandard>stdcpp17</LanguageStandard>
<LanguageStandard_C>stdc17</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;include/nsis/pluginapi.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="nsis\api.h" />
<ClInclude Include="nsis\pluginapi.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="SemverCompare.cpp" />
</ItemGroup>
<ItemGroup>
<Library Include="include\nsis\pluginapi.lib" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="nsis\api.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nsis\pluginapi.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="SemverCompare.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Library Include="include\nsis\pluginapi.lib" />
</ItemGroup>
</Project>

View File

@@ -1 +0,0 @@
msbuild ./SemverCompare.sln /p:Configuration=Debug

View File

@@ -1 +0,0 @@
msbuild ./SemverCompare.sln /p:Configuration=Release

16
demo.nsi Normal file
View File

@@ -0,0 +1,16 @@
Name "demo"
OutFile "demo.exe"
ShowInstDetails show
Unicode true
!addplugindir ".\target\release"
!addplugindir ".\target\debug"
!addplugindir ".\target\i686-pc-windows-msvc\release"
!addplugindir ".\target\i686-pc-windows-msvc\debug"
Section
nsis_semvercompare::SemverCompare "1.0.0" "1.1.0"
Pop $1
DetailPrint $1
SectionEnd

View File

@@ -1,86 +0,0 @@
/*
* apih
*
* This file is a part of NSIS.
*
* Copyright (C) 1999-2009 Nullsoft and Contributors
*
* Licensed under the zlib/libpng license (the "License");
* you may not use this file except in compliance with the License.
*
* Licence details can be found in the file COPYING.
*
* This software is provided 'as-is', without any express or implied
* warranty.
*/
#ifndef _NSIS_EXEHEAD_API_H_
#define _NSIS_EXEHEAD_API_H_
// Starting with NSIS 2.42, you can check the version of the plugin API in
// exec_flags->plugin_api_version The format is 0xXXXXYYYY where X is the major
// version and Y is the minor version (MAKELONG(y,x)) When doing version checks,
// always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >=
// NSISPIAPIVER_1_0) {}
#define NSISPIAPIVER_1_0 0x00010000
#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0
// NSIS Plug-In Callback Messages
enum NSPIM {
NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup
NSPIM_GUIUNLOAD, // Called after .onGUIEnd
};
// Prototype for callbacks registered with
// extra_parameters->RegisterPluginCallback() Return NULL for unknown messages
// Should always be __cdecl for future expansion possibilities
typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM);
// extra_parameters data structures containing other interesting stuff
// but the stack, variables and HWND passed on to plug-ins.
typedef struct {
int autoclose;
int all_user_var;
int exec_error;
int abort;
int exec_reboot; // NSIS_SUPPORT_REBOOT
int reboot_called; // NSIS_SUPPORT_REBOOT
int XXX_cur_insttype; // depreacted
int plugin_api_version; // see NSISPIAPIVER_CURR
// used to be XXX_insttype_changed
int silent; // NSIS_CONFIG_SILENT_SUPPORT
int instdir_error;
int rtl;
int errlvl;
int alter_reg_view;
int status_update;
} exec_flags_t;
#ifndef NSISCALL
#define NSISCALL __stdcall
#endif
typedef struct {
exec_flags_t* exec_flags;
int(NSISCALL* ExecuteCodeSegment)(int, HWND);
void(NSISCALL* validate_filename)(TCHAR*);
int(NSISCALL* RegisterPluginCallback)(
HMODULE,
NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and
// < 0 on errors
} extra_parameters;
// Definitions for page showing plug-ins
// See Ui.c to understand better how they're used
// sent to the outer window to tell it to go to the next inner window
#define WM_NOTIFY_OUTER_NEXT (WM_USER + 0x8)
// custom pages should send this message to let NSIS know they're ready
#define WM_NOTIFY_CUSTOM_READY (WM_USER + 0xd)
// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning
#define NOTIFY_BYE_BYE 'x'
#endif /* _PLUGIN_H_ */

View File

@@ -1,214 +0,0 @@
/*
* nsis_tchar.h
*
* This file is a part of NSIS.
*
* Copyright (C) 1999-2007 Nullsoft and Contributors
*
* This software is provided 'as-is', without any express or implied
* warranty.
*
* For Unicode support by Jim Park -- 08/30/2007
*/
// Jim Park: Only those we use are listed here.
#pragma once
#ifdef _UNICODE
#ifndef _T
#define __T(x) L##x
#define _T(x) __T(x)
#define _TEXT(x) __T(x)
#endif
typedef wchar_t TCHAR;
typedef wchar_t _TUCHAR;
// program
#define _tmain wmain
#define _tWinMain wWinMain
#define _tenviron _wenviron
#define __targv __wargv
// printfs
#define _ftprintf fwprintf
#define _sntprintf _snwprintf
#define _stprintf _swprintf
#define _tprintf wprintf
#define _vftprintf vfwprintf
#define _vsntprintf _vsnwprintf
#define _vstprintf _vswprintf
// scanfs
#define _tscanf wscanf
#define _stscanf swscanf
// string manipulations
#define _tcscat wcscat
#define _tcschr wcschr
#define _tcsclen wcslen
#define _tcscpy wcscpy
#define _tcsdup _wcsdup
#define _tcslen wcslen
#define _tcsnccpy wcsncpy
#define _tcsncpy wcsncpy
#define _tcsrchr wcsrchr
#define _tcsstr wcsstr
#define _tcstok wcstok
// string comparisons
#define _tcscmp wcscmp
#define _tcsicmp _wcsicmp
#define _tcsncicmp _wcsnicmp
#define _tcsncmp wcsncmp
#define _tcsnicmp _wcsnicmp
// upper / lower
#define _tcslwr _wcslwr
#define _tcsupr _wcsupr
#define _totlower towlower
#define _totupper towupper
// conversions to numbers
#define _tcstoi64 _wcstoi64
#define _tcstol wcstol
#define _tcstoul wcstoul
#define _tstof _wtof
#define _tstoi _wtoi
#define _tstoi64 _wtoi64
#define _ttoi _wtoi
#define _ttoi64 _wtoi64
#define _ttol _wtol
// conversion from numbers to strings
#define _itot _itow
#define _ltot _ltow
#define _i64tot _i64tow
#define _ui64tot _ui64tow
// file manipulations
#define _tfopen _wfopen
#define _topen _wopen
#define _tremove _wremove
#define _tunlink _wunlink
// reading and writing to i/o
#define _fgettc fgetwc
#define _fgetts fgetws
#define _fputts fputws
#define _gettchar getwchar
// directory
#define _tchdir _wchdir
// environment
#define _tgetenv _wgetenv
#define _tsystem _wsystem
// time
#define _tcsftime wcsftime
#else // ANSI
#ifndef _T
#define _T(x) x
#define _TEXT(x) x
#endif
typedef char TCHAR;
typedef unsigned char _TUCHAR;
// program
#define _tmain main
#define _tWinMain WinMain
#define _tenviron environ
#define __targv __argv
// printfs
#define _ftprintf fprintf
#define _sntprintf _snprintf
#define _stprintf sprintf
#define _tprintf printf
#define _vftprintf vfprintf
#define _vsntprintf _vsnprintf
#define _vstprintf vsprintf
// scanfs
#define _tscanf scanf
#define _stscanf sscanf
// string manipulations
#define _tcscat strcat
#define _tcschr strchr
#define _tcsclen strlen
#define _tcscnlen strnlen
#define _tcscpy strcpy
#define _tcsdup _strdup
#define _tcslen strlen
#define _tcsnccpy strncpy
#define _tcsrchr strrchr
#define _tcsstr strstr
#define _tcstok strtok
// string comparisons
#define _tcscmp strcmp
#define _tcsicmp _stricmp
#define _tcsncmp strncmp
#define _tcsncicmp _strnicmp
#define _tcsnicmp _strnicmp
// upper / lower
#define _tcslwr _strlwr
#define _tcsupr _strupr
#define _totupper toupper
#define _totlower tolower
// conversions to numbers
#define _tcstol strtol
#define _tcstoul strtoul
#define _tstof atof
#define _tstoi atoi
#define _tstoi64 _atoi64
#define _tstoi64 _atoi64
#define _ttoi atoi
#define _ttoi64 _atoi64
#define _ttol atol
// conversion from numbers to strings
#define _i64tot _i64toa
#define _itot _itoa
#define _ltot _ltoa
#define _ui64tot _ui64toa
// file manipulations
#define _tfopen fopen
#define _topen _open
#define _tremove remove
#define _tunlink _unlink
// reading and writing to i/o
#define _fgettc fgetc
#define _fgetts fgets
#define _fputts fputs
#define _gettchar getchar
// directory
#define _tchdir _chdir
// environment
#define _tgetenv getenv
#define _tsystem system
// time
#define _tcsftime strftime
#endif
// is functions (the same in Unicode / ANSI)
#define _istgraph isgraph
#define _istascii __isascii
#define __TFILE__ _T(__FILE__)
#define __TDATE__ _T(__DATE__)
#define __TTIME__ _T(__TIME__)

View File

@@ -1,105 +0,0 @@
#ifndef ___NSIS_PLUGIN__H___
#define ___NSIS_PLUGIN__H___
#ifdef __cplusplus
extern "C" {
#endif
#include "api.h"
#include "nsis_tchar.h"
#ifndef NSISCALL
#define NSISCALL __stdcall
#endif
#define EXDLL_INIT() \
{ \
g_stringsize = string_size; \
g_stacktop = stacktop; \
g_variables = variables; \
}
typedef struct _stack_t {
struct _stack_t* next;
TCHAR text[1]; // this should be the length of string_size
} stack_t;
enum {
INST_0, // $0
INST_1, // $1
INST_2, // $2
INST_3, // $3
INST_4, // $4
INST_5, // $5
INST_6, // $6
INST_7, // $7
INST_8, // $8
INST_9, // $9
INST_R0, // $R0
INST_R1, // $R1
INST_R2, // $R2
INST_R3, // $R3
INST_R4, // $R4
INST_R5, // $R5
INST_R6, // $R6
INST_R7, // $R7
INST_R8, // $R8
INST_R9, // $R9
INST_CMDLINE, // $CMDLINE
INST_INSTDIR, // $INSTDIR
INST_OUTDIR, // $OUTDIR
INST_EXEDIR, // $EXEDIR
INST_LANG, // $LANGUAGE
__INST_LAST
};
extern unsigned int g_stringsize;
extern stack_t** g_stacktop;
extern TCHAR* g_variables;
int NSISCALL popstring(TCHAR* str); // 0 on success, 1 on empty stack
int NSISCALL
popstringn(TCHAR* str,
int maxlen); // with length limit, pass 0 for g_stringsize
int NSISCALL popint(); // pops an integer
int NSISCALL popint_or(); // with support for or'ing (2|4|8)
int NSISCALL myatoi(const TCHAR* s); // converts a string to an integer
unsigned NSISCALL myatou(
const TCHAR* s); // converts a string to an unsigned integer, decimal only
int NSISCALL myatoi_or(const TCHAR* s); // with support for or'ing (2|4|8)
void NSISCALL pushstring(const TCHAR* str);
void NSISCALL pushint(int value);
TCHAR* NSISCALL getuservariable(const int varnum);
void NSISCALL setuservariable(const int varnum, const TCHAR* var);
#ifdef _UNICODE
#define PopStringW(x) popstring(x)
#define PushStringW(x) pushstring(x)
#define SetUserVariableW(x, y) setuservariable(x, y)
int NSISCALL PopStringA(char* ansiStr);
void NSISCALL PushStringA(const char* ansiStr);
void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr);
#else
// ANSI defs
#define PopStringA(x) popstring(x)
#define PushStringA(x) pushstring(x)
#define SetUserVariableA(x, y) setuservariable(x, y)
int NSISCALL PopStringW(wchar_t* wideStr);
void NSISCALL PushStringW(wchar_t* wideStr);
void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr);
#endif
#ifdef __cplusplus
}
#endif
#endif //!___NSIS_PLUGIN__H___

Binary file not shown.

View File

@@ -1,935 +0,0 @@
// _____ _ _
// / ____| | | (_)
// | (___ ___ _ __ ___ __ _ _ __ | |_ _ ___
// \___ \ / _ \ '_ ` _ \ / _` | '_ \| __| |/ __|
// ____) | __/ | | | | | (_| | | | | |_| | (__
// |_____/ \___|_| |_| |_|\__,_|_| |_|\__|_|\___|
// __ __ _ _ _____
// \ \ / / (_) (_) / ____|_ _
// \ \ / /__ _ __ ___ _ ___ _ __ _ _ __ __ _ | | _| |_ _| |_
// \ \/ / _ \ '__/ __| |/ _ \| '_ \| | '_ \ / _` | | | |_ _|_ _|
// \ / __/ | \__ \ | (_) | | | | | | | | (_| | | |____|_| |_|
// \/ \___|_| |___/_|\___/|_| |_|_|_| |_|\__, | \_____|
// https://github.com/Neargye/semver __/ |
// version 0.3.0 |___/
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2021 Daniil Goncharov <neargye@gmail.com>.
// Copyright (c) 2020 - 2021 Alexander Gorbunov <naratzul@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef NEARGYE_SEMANTIC_VERSIONING_HPP
#define NEARGYE_SEMANTIC_VERSIONING_HPP
#define SEMVER_VERSION_MAJOR 0
#define SEMVER_VERSION_MINOR 3
#define SEMVER_VERSION_PATCH 0
#include <cstddef>
#include <cstdint>
#include <iosfwd>
#include <limits>
#include <optional>
#include <string>
#include <string_view>
#if __has_include(<charconv>)
#include <charconv>
#else
#include <system_error>
#endif
#if defined(SEMVER_CONFIG_FILE)
#include SEMVER_CONFIG_FILE
#endif
#if defined(SEMVER_THROW)
// define SEMVER_THROW(msg) to override semver throw behavior.
#elif defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
#include <stdexcept>
#define SEMVER_THROW(msg) (throw std::invalid_argument{msg})
#else
#include <cassert>
#include <cstdlib>
#define SEMVER_THROW(msg) (assert(!msg), std::abort())
#endif
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored \
"-Wmissing-braces" // Ignore warning: suggest braces around initialization
// of subobject 'return {first,
// std::errc::invalid_argument};'.
#endif
namespace semver {
enum struct prerelease : std::uint8_t { alpha = 0, beta = 1, rc = 2, none = 3 };
#if __has_include(<charconv>)
struct from_chars_result : std::from_chars_result {
[[nodiscard]] constexpr operator bool() const noexcept {
return ec == std::errc{};
}
};
struct to_chars_result : std::to_chars_result {
[[nodiscard]] constexpr operator bool() const noexcept {
return ec == std::errc{};
}
};
#else
struct from_chars_result {
const char* ptr;
std::errc ec;
[[nodiscard]] constexpr operator bool() const noexcept {
return ec == std::errc{};
}
};
struct to_chars_result {
char* ptr;
std::errc ec;
[[nodiscard]] constexpr operator bool() const noexcept {
return ec == std::errc{};
}
};
#endif
// Max version string length = 3(<major>) + 1(.) + 3(<minor>) + 1(.) +
// 3(<patch>) + 1(-) + 5(<prerelease>) + 1(.) + 3(<prereleaseversion>) = 21.
inline constexpr auto max_version_string_length = std::size_t{21};
namespace detail {
inline constexpr auto alpha = std::string_view{"alpha", 5};
inline constexpr auto beta = std::string_view{"beta", 4};
inline constexpr auto rc = std::string_view{"rc", 2};
// Min version string length = 1(<major>) + 1(.) + 1(<minor>) + 1(.) +
// 1(<patch>) = 5.
inline constexpr auto min_version_string_length = 5;
constexpr char to_lower(char c) noexcept {
return (c >= 'A' && c <= 'Z') ? static_cast<char>(c + ('a' - 'A')) : c;
}
constexpr bool is_digit(char c) noexcept {
return c >= '0' && c <= '9';
}
constexpr bool is_space(char c) noexcept {
return c == ' ';
}
constexpr bool is_operator(char c) noexcept {
return c == '<' || c == '>' || c == '=';
}
constexpr bool is_dot(char c) noexcept {
return c == '.';
}
constexpr bool is_logical_or(char c) noexcept {
return c == '|';
}
constexpr bool is_hyphen(char c) noexcept {
return c == '-';
}
constexpr bool is_letter(char c) noexcept {
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
constexpr std::uint8_t to_digit(char c) noexcept {
return static_cast<std::uint8_t>(c - '0');
}
constexpr std::uint8_t length(std::uint8_t x) noexcept {
return x < 10 ? 1 : (x < 100 ? 2 : 3);
}
constexpr std::uint8_t length(prerelease t) noexcept {
if (t == prerelease::alpha) {
return static_cast<std::uint8_t>(alpha.length());
} else if (t == prerelease::beta) {
return static_cast<std::uint8_t>(beta.length());
} else if (t == prerelease::rc) {
return static_cast<std::uint8_t>(rc.length());
}
return 0;
}
constexpr bool equals(const char* first,
const char* last,
std::string_view str) noexcept {
for (std::size_t i = 0; first != last && i < str.length(); ++i, ++first) {
if (to_lower(*first) != to_lower(str[i])) {
return false;
}
}
return true;
}
constexpr char* to_chars(char* str, std::uint8_t x, bool dot = true) noexcept {
do {
*(--str) = static_cast<char>('0' + (x % 10));
x /= 10;
} while (x != 0);
if (dot) {
*(--str) = '.';
}
return str;
}
constexpr char* to_chars(char* str, prerelease t) noexcept {
const auto p = t == prerelease::alpha ? alpha
: t == prerelease::beta ? beta
: t == prerelease::rc ? rc
: std::string_view{};
if (p.size() > 0) {
for (auto it = p.rbegin(); it != p.rend(); ++it) {
*(--str) = *it;
}
*(--str) = '-';
}
return str;
}
constexpr const char* from_chars(const char* first,
const char* last,
std::uint8_t& d) noexcept {
if (first != last && is_digit(*first)) {
std::int32_t t = 0;
for (; first != last && is_digit(*first); ++first) {
t = t * 10 + to_digit(*first);
}
if (t <= (std::numeric_limits<std::uint8_t>::max)()) {
d = static_cast<std::uint8_t>(t);
return first;
}
}
return nullptr;
}
constexpr const char* from_chars(const char* first,
const char* last,
std::optional<std::uint8_t>& d) noexcept {
if (first != last && is_digit(*first)) {
std::int32_t t = 0;
for (; first != last && is_digit(*first); ++first) {
t = t * 10 + to_digit(*first);
}
if (t <= (std::numeric_limits<std::uint8_t>::max)()) {
d = static_cast<std::uint8_t>(t);
return first;
}
}
return nullptr;
}
constexpr const char* from_chars(const char* first,
const char* last,
prerelease& p) noexcept {
if (is_hyphen(*first)) {
++first;
}
if (equals(first, last, alpha)) {
p = prerelease::alpha;
return first + alpha.length();
} else if (equals(first, last, beta)) {
p = prerelease::beta;
return first + beta.length();
} else if (equals(first, last, rc)) {
p = prerelease::rc;
return first + rc.length();
}
return nullptr;
}
constexpr bool check_delimiter(const char* first,
const char* last,
char d) noexcept {
return first != last && first != nullptr && *first == d;
}
template <typename T, typename = void>
struct resize_uninitialized {
static auto resize(T& str, std::size_t size)
-> std::void_t<decltype(str.resize(size))> {
str.resize(size);
}
};
template <typename T>
struct resize_uninitialized<
T,
std::void_t<decltype(std::declval<T>().__resize_default_init(42))>> {
static void resize(T& str, std::size_t size) {
str.__resize_default_init(size);
}
};
} // namespace detail
struct version {
std::uint8_t major = 0;
std::uint8_t minor = 1;
std::uint8_t patch = 0;
prerelease prerelease_type = prerelease::none;
std::optional<std::uint8_t> prerelease_number = std::nullopt;
constexpr version(std::uint8_t mj,
std::uint8_t mn,
std::uint8_t pt,
prerelease prt = prerelease::none,
std::optional<std::uint8_t> prn = std::nullopt) noexcept
: major{mj},
minor{mn},
patch{pt},
prerelease_type{prt},
prerelease_number{prt == prerelease::none ? std::nullopt : prn} {}
explicit constexpr version(std::string_view str)
: version(0, 0, 0, prerelease::none, 0) {
from_string(str);
}
constexpr version() =
default; // https://semver.org/#how-should-i-deal-with-revisions-in-the-0yz-initial-development-phase
constexpr version(const version&) = default;
constexpr version(version&&) = default;
~version() = default;
version& operator=(const version&) = default;
version& operator=(version&&) = default;
[[nodiscard]] constexpr from_chars_result from_chars(
const char* first,
const char* last) noexcept {
if (first == nullptr || last == nullptr ||
(last - first) < detail::min_version_string_length) {
return {first, std::errc::invalid_argument};
}
auto next = first;
if (next = detail::from_chars(next, last, major);
detail::check_delimiter(next, last, '.')) {
if (next = detail::from_chars(++next, last, minor);
detail::check_delimiter(next, last, '.')) {
if (next = detail::from_chars(++next, last, patch); next == last) {
prerelease_type = prerelease::none;
prerelease_number = {};
return {next, std::errc{}};
} else if (detail::check_delimiter(next, last, '-')) {
if (next = detail::from_chars(next, last, prerelease_type);
next == last) {
prerelease_number = {};
return {next, std::errc{}};
} else if (detail::check_delimiter(next, last, '.')) {
if (next = detail::from_chars(++next, last, prerelease_number);
next == last) {
return {next, std::errc{}};
}
}
}
}
}
return {first, std::errc::invalid_argument};
}
[[nodiscard]] constexpr to_chars_result to_chars(char* first,
char* last) const noexcept {
const auto length = string_length();
if (first == nullptr || last == nullptr || (last - first) < length) {
return {last, std::errc::value_too_large};
}
auto next = first + length;
if (prerelease_type != prerelease::none) {
if (prerelease_number.has_value()) {
next = detail::to_chars(next, prerelease_number.value());
}
next = detail::to_chars(next, prerelease_type);
}
next = detail::to_chars(next, patch);
next = detail::to_chars(next, minor);
next = detail::to_chars(next, major, false);
return {first + length, std::errc{}};
}
[[nodiscard]] constexpr bool from_string_noexcept(
std::string_view str) noexcept {
return from_chars(str.data(), str.data() + str.length());
}
constexpr version& from_string(std::string_view str) {
if (!from_string_noexcept(str)) {
SEMVER_THROW("semver::version::from_string invalid version.");
}
return *this;
}
[[nodiscard]] std::string to_string() const {
auto str = std::string{};
detail::resize_uninitialized<std::string>::resize(str, string_length());
if (!to_chars(str.data(), str.data() + str.length())) {
SEMVER_THROW("semver::version::to_string invalid version.");
}
return str;
}
[[nodiscard]] constexpr std::uint8_t string_length() const noexcept {
// (<major>) + 1(.) + (<minor>) + 1(.) + (<patch>)
auto length = detail::length(major) + detail::length(minor) +
detail::length(patch) + 2;
if (prerelease_type != prerelease::none) {
// + 1(-) + (<prerelease>)
length += detail::length(prerelease_type) + 1;
if (prerelease_number.has_value()) {
// + 1(.) + (<prereleaseversion>)
length += detail::length(prerelease_number.value()) + 1;
}
}
return static_cast<std::uint8_t>(length);
}
[[nodiscard]] constexpr int compare(const version& other) const noexcept {
if (major != other.major) {
return major - other.major;
}
if (minor != other.minor) {
return minor - other.minor;
}
if (patch != other.patch) {
return patch - other.patch;
}
if (prerelease_type != other.prerelease_type) {
return static_cast<std::uint8_t>(prerelease_type) -
static_cast<std::uint8_t>(other.prerelease_type);
}
if (prerelease_number.has_value()) {
if (other.prerelease_number.has_value()) {
return prerelease_number.value() - other.prerelease_number.value();
}
return 1;
} else if (other.prerelease_number.has_value()) {
return -1;
}
return 0;
}
};
[[nodiscard]] constexpr bool operator==(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) == 0;
}
[[nodiscard]] constexpr bool operator!=(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) != 0;
}
[[nodiscard]] constexpr bool operator>(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) > 0;
}
[[nodiscard]] constexpr bool operator>=(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) >= 0;
}
[[nodiscard]] constexpr bool operator<(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) < 0;
}
[[nodiscard]] constexpr bool operator<=(const version& lhs,
const version& rhs) noexcept {
return lhs.compare(rhs) <= 0;
}
[[nodiscard]] constexpr version operator""_version(const char* str,
std::size_t length) {
return version{std::string_view{str, length}};
}
[[nodiscard]] constexpr bool valid(std::string_view str) noexcept {
return version{}.from_string_noexcept(str);
}
[[nodiscard]] constexpr from_chars_result from_chars(const char* first,
const char* last,
version& v) noexcept {
return v.from_chars(first, last);
}
[[nodiscard]] constexpr to_chars_result to_chars(char* first,
char* last,
const version& v) noexcept {
return v.to_chars(first, last);
}
[[nodiscard]] constexpr std::optional<version> from_string_noexcept(
std::string_view str) noexcept {
if (version v{}; v.from_string_noexcept(str)) {
return v;
}
return std::nullopt;
}
[[nodiscard]] constexpr version from_string(std::string_view str) {
return version{str};
}
[[nodiscard]] inline std::string to_string(const version& v) {
return v.to_string();
}
template <typename Char, typename Traits>
inline std::basic_ostream<Char, Traits>& operator<<(
std::basic_ostream<Char, Traits>& os,
const version& v) {
for (const auto c : v.to_string()) {
os.put(c);
}
return os;
}
inline namespace comparators {
enum struct comparators_option : std::uint8_t {
exclude_prerelease,
include_prerelease
};
[[nodiscard]] constexpr int compare(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
if (option == comparators_option::exclude_prerelease) {
return version{lhs.major, lhs.minor, lhs.patch}.compare(
version{rhs.major, rhs.minor, rhs.patch});
}
return lhs.compare(rhs);
}
[[nodiscard]] constexpr bool equal_to(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) == 0;
}
[[nodiscard]] constexpr bool not_equal_to(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) != 0;
}
[[nodiscard]] constexpr bool greater(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) > 0;
}
[[nodiscard]] constexpr bool greater_equal(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) >= 0;
}
[[nodiscard]] constexpr bool less(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) < 0;
}
[[nodiscard]] constexpr bool less_equal(
const version& lhs,
const version& rhs,
comparators_option option =
comparators_option::include_prerelease) noexcept {
return compare(lhs, rhs, option) <= 0;
}
} // namespace comparators
namespace range {
namespace detail {
using namespace semver::detail;
class range {
public:
constexpr explicit range(std::string_view str) noexcept : parser{str} {}
constexpr bool satisfies(const version& ver, bool include_prerelease) {
const bool has_prerelease = ver.prerelease_type != prerelease::none;
do {
if (is_logical_or_token()) {
parser.advance_token(range_token_type::logical_or);
}
bool contains = true;
bool allow_compare = include_prerelease;
while (is_operator_token() || is_number_token()) {
const auto range = parser.parse_range();
const bool equal_without_tags =
equal_to(range.ver, ver, comparators_option::exclude_prerelease);
if (has_prerelease && equal_without_tags) {
allow_compare = true;
}
if (!range.satisfies(ver)) {
contains = false;
break;
}
}
if (has_prerelease) {
if (allow_compare && contains) {
return true;
}
} else if (contains) {
return true;
}
} while (is_logical_or_token());
return false;
}
private:
enum struct range_operator : std::uint8_t {
less,
less_or_equal,
greater,
greater_or_equal,
equal
};
struct range_comparator {
range_operator op;
version ver;
constexpr bool satisfies(const version& version) const {
switch (op) {
case range_operator::equal:
return version == ver;
case range_operator::greater:
return version > ver;
case range_operator::greater_or_equal:
return version >= ver;
case range_operator::less:
return version < ver;
case range_operator::less_or_equal:
return version <= ver;
default:
SEMVER_THROW("semver::range unexpected operator.");
}
}
};
enum struct range_token_type : std::uint8_t {
none,
number,
range_operator,
dot,
logical_or,
hyphen,
prerelease,
end_of_line
};
struct range_token {
range_token_type type = range_token_type::none;
std::uint8_t number = 0;
range_operator op = range_operator::equal;
prerelease prerelease_type = prerelease::none;
};
struct range_lexer {
std::string_view text;
std::size_t pos;
constexpr explicit range_lexer(std::string_view text) noexcept
: text{text}, pos{0} {}
constexpr range_token get_next_token() noexcept {
while (!end_of_line()) {
if (is_space(text[pos])) {
advance(1);
continue;
}
if (is_logical_or(text[pos])) {
advance(2);
return {range_token_type::logical_or};
}
if (is_operator(text[pos])) {
const auto op = get_operator();
return {range_token_type::range_operator, 0, op};
}
if (is_digit(text[pos])) {
const auto number = get_number();
return {range_token_type::number, number};
}
if (is_dot(text[pos])) {
advance(1);
return {range_token_type::dot};
}
if (is_hyphen(text[pos])) {
advance(1);
return {range_token_type::hyphen};
}
if (is_letter(text[pos])) {
const auto prerelease = get_prerelease();
return {range_token_type::prerelease, 0, range_operator::equal,
prerelease};
}
}
return {range_token_type::end_of_line};
}
constexpr bool end_of_line() const noexcept { return pos >= text.length(); }
constexpr void advance(std::size_t i) noexcept { pos += i; }
constexpr range_operator get_operator() noexcept {
if (text[pos] == '<') {
advance(1);
if (text[pos] == '=') {
advance(1);
return range_operator::less_or_equal;
}
return range_operator::less;
} else if (text[pos] == '>') {
advance(1);
if (text[pos] == '=') {
advance(1);
return range_operator::greater_or_equal;
}
return range_operator::greater;
} else if (text[pos] == '=') {
advance(1);
return range_operator::equal;
}
return range_operator::equal;
}
constexpr std::uint8_t get_number() noexcept {
const auto first = text.data() + pos;
const auto last = text.data() + text.length();
if (std::uint8_t n{}; from_chars(first, last, n) != nullptr) {
advance(length(n));
return n;
}
return 0;
}
constexpr prerelease get_prerelease() noexcept {
const auto first = text.data() + pos;
const auto last = text.data() + text.length();
if (first > last) {
advance(1);
return prerelease::none;
}
if (prerelease p{}; from_chars(first, last, p) != nullptr) {
advance(length(p));
return p;
}
advance(1);
return prerelease::none;
}
};
struct range_parser {
range_lexer lexer;
range_token current_token;
constexpr explicit range_parser(std::string_view str)
: lexer{str}, current_token{range_token_type::none} {
advance_token(range_token_type::none);
}
constexpr void advance_token(range_token_type token_type) {
if (current_token.type != token_type) {
SEMVER_THROW("semver::range unexpected token.");
}
current_token = lexer.get_next_token();
}
constexpr range_comparator parse_range() {
if (current_token.type == range_token_type::number) {
const auto version = parse_version();
return {range_operator::equal, version};
} else if (current_token.type == range_token_type::range_operator) {
const auto range_operator = current_token.op;
advance_token(range_token_type::range_operator);
const auto version = parse_version();
return {range_operator, version};
}
return {range_operator::equal, version{}};
}
constexpr version parse_version() {
const auto major = parse_number();
advance_token(range_token_type::dot);
const auto minor = parse_number();
advance_token(range_token_type::dot);
const auto patch = parse_number();
prerelease prerelease = prerelease::none;
std::optional<std::uint8_t> prerelease_number = std::nullopt;
if (current_token.type == range_token_type::hyphen) {
advance_token(range_token_type::hyphen);
prerelease = parse_prerelease();
if (current_token.type == range_token_type::dot) {
advance_token(range_token_type::dot);
prerelease_number = parse_number();
}
}
return {major, minor, patch, prerelease, prerelease_number};
}
constexpr std::uint8_t parse_number() {
const auto token = current_token;
advance_token(range_token_type::number);
return token.number;
}
constexpr prerelease parse_prerelease() {
const auto token = current_token;
advance_token(range_token_type::prerelease);
return token.prerelease_type;
}
};
[[nodiscard]] constexpr bool is_logical_or_token() const noexcept {
return parser.current_token.type == range_token_type::logical_or;
}
[[nodiscard]] constexpr bool is_operator_token() const noexcept {
return parser.current_token.type == range_token_type::range_operator;
}
[[nodiscard]] constexpr bool is_number_token() const noexcept {
return parser.current_token.type == range_token_type::number;
}
range_parser parser;
};
} // namespace detail
enum struct satisfies_option : std::uint8_t {
exclude_prerelease,
include_prerelease
};
constexpr bool satisfies(
const version& ver,
std::string_view str,
satisfies_option option = satisfies_option::exclude_prerelease) {
switch (option) {
case satisfies_option::exclude_prerelease:
return detail::range{str}.satisfies(ver, false);
case satisfies_option::include_prerelease:
return detail::range{str}.satisfies(ver, true);
default:
SEMVER_THROW("semver::range unexpected satisfies_option.");
}
}
} // namespace range
// Version lib semver.
inline constexpr auto semver_version =
version{SEMVER_VERSION_MAJOR, SEMVER_VERSION_MINOR, SEMVER_VERSION_PATCH};
} // namespace semver
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // NEARGYE_SEMANTIC_VERSIONING_HPP

71
src/lib.rs Normal file
View File

@@ -0,0 +1,71 @@
mod utils;
use std::str::FromStr;
use semver::Version;
use utils::{exdll_init, popstring, pushint, stack_t, wchar_t};
use windows_sys::Win32::Foundation::HWND;
#[no_mangle]
pub unsafe extern "C" fn SemverCompare(
_hwnd_parent: HWND,
string_size: u32,
variables: *mut wchar_t,
stacktop: *mut *mut stack_t,
) {
exdll_init(string_size, variables, stacktop);
let v1 = popstring().unwrap();
let v2 = popstring().unwrap();
let ret = semver_compare(&v1, &v2);
pushint(ret);
}
fn semver_compare(v1: &str, v2: &str) -> i32 {
let v1 = Version::from_str(&v1);
let v2 = Version::from_str(&v2);
let (v1, v2) = match (v1, v2) {
(Ok(_), Err(_)) => return 1,
(Err(_), Err(_)) => return 0,
(Err(_), Ok(_)) => return -1,
(Ok(v1), Ok(v2)) => (v1, v2),
};
if v1 > v2 {
1
} else if v1 == v2 {
0
} else if v1 < v2 {
-1
} else {
0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
for (v1, v2, ret) in [
("1.2.1", "1.2.0", 1),
("1.2.0", "1.2.1", -1),
("1.2.1", "1.2.1", 0),
("1.2.1-alpha.1", "1.2.1-beta.5", -1),
("1.2.1-rc.1", "1.2.1-beta.1", 1),
("1.2.1-alpha.1", "1.2.1-alpha.1", 0),
("1.2qe2.1-alpha.1", "1.2.1-alpha.1", -1),
("1.2.1-alpha.1", "-q1.2.1-alpha.1", 1),
("1.2.saf1-alpha.1", "-q1.2.1-alpha.1", 0),
("1.0.0-aluc.0", "1.0.0", -1),
(" 1.0.0-aluc.1", "1.0.0-bdfsf.0", -1),
("1.2.1-fffasd.1", "1.2.1-dasdqwe.1", 1),
("1.2.1-gasfdlkj.1", "1.2.1-calskjd.1", 1),
] {
assert_eq!(semver_compare(v1, v2), ret);
}
}
}

82
src/utils.rs Normal file
View File

@@ -0,0 +1,82 @@
#![allow(non_camel_case_types)]
use std::{
ffi::{OsStr, OsString},
iter::once,
mem::{size_of, size_of_val},
os::windows::prelude::{OsStrExt, OsStringExt},
};
use windows_sys::Win32::{
Globalization::{lstrcpyW, lstrcpynW},
System::Memory::{GlobalAlloc, GlobalFree, GPTR},
};
static mut G_STRINGSIZE: u32 = 0;
static mut G_VARIABLES: *mut wchar_t = std::ptr::null_mut();
static mut G_STACKTOP: *mut *mut stack_t = std::ptr::null_mut();
pub unsafe fn exdll_init(string_size: u32, variables: *mut wchar_t, stacktop: *mut *mut stack_t) {
G_STRINGSIZE = string_size;
G_VARIABLES = variables;
G_STACKTOP = stacktop;
}
pub type wchar_t = i32;
#[repr(C)]
#[derive(Debug)]
pub struct stack_t {
next: *mut stack_t,
text: [wchar_t; 1],
}
pub unsafe fn pushstring(s: impl AsRef<OsStr>) {
if G_STACKTOP.is_null() {
return;
}
let string_wide = encode_wide(s);
let th: *mut stack_t = GlobalAlloc(
GPTR,
size_of::<stack_t>() + G_STRINGSIZE as usize * size_of_val(&string_wide),
) as _;
lstrcpynW(
(*th).text.as_ptr() as _,
string_wide.as_ptr() as _,
G_STRINGSIZE as _,
);
(*th).next = *G_STACKTOP;
*G_STACKTOP = th;
}
pub unsafe fn popstring() -> Result<String, ()> {
if G_STACKTOP.is_null() || (*G_STACKTOP).is_null() {
return Err(());
}
let mut string_wide: Vec<u16> = vec![0; G_STRINGSIZE as _];
let th: *mut stack_t = *G_STACKTOP;
lstrcpyW(string_wide.as_mut_ptr(), (*th).text.as_ptr() as _);
let string = decode_wide(&string_wide).to_str().ok_or(())?.to_string();
*G_STACKTOP = (*th).next;
GlobalFree(th as _);
Ok(string)
}
pub unsafe fn pushint(int: i32) {
pushstring(int.to_string())
}
fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
string.as_ref().encode_wide().chain(once(0)).collect()
}
pub fn decode_wide(mut wide_c_string: &[u16]) -> OsString {
if let Some(null_pos) = wide_c_string.iter().position(|c| *c == 0) {
wide_c_string = &wide_c_string[..null_pos];
}
OsString::from_wide(wide_c_string)
}