Moved Natural String Sort functions into MUtils library.
This commit is contained in:
parent
52b230f2db
commit
a0707809f5
@ -15,6 +15,7 @@
|
|||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="src\3rd_party\strnatcmp\src\strnatcmp.cpp" />
|
||||||
<ClCompile Include="src\CPUFeatures_Win32.cpp" />
|
<ClCompile Include="src\CPUFeatures_Win32.cpp" />
|
||||||
<ClCompile Include="src\DLLMain.cpp" />
|
<ClCompile Include="src\DLLMain.cpp" />
|
||||||
<ClCompile Include="src\ErrorHandler_Win32.cpp" />
|
<ClCompile Include="src\ErrorHandler_Win32.cpp" />
|
||||||
@ -38,6 +39,8 @@
|
|||||||
<ClInclude Include="include\MUtils\OSSupport.h" />
|
<ClInclude Include="include\MUtils\OSSupport.h" />
|
||||||
<ClInclude Include="include\MUtils\Startup.h" />
|
<ClInclude Include="include\MUtils\Startup.h" />
|
||||||
<ClInclude Include="include\MUtils\Terminal.h" />
|
<ClInclude Include="include\MUtils\Terminal.h" />
|
||||||
|
<ClInclude Include="src\3rd_party\keccak\include\keccak_impl.h" />
|
||||||
|
<ClInclude Include="src\3rd_party\strnatcmp\include\strnatcmp.h" />
|
||||||
<ClInclude Include="src\DirLocker.h" />
|
<ClInclude Include="src\DirLocker.h" />
|
||||||
<ClInclude Include="src\Utils_Win32.h" />
|
<ClInclude Include="src\Utils_Win32.h" />
|
||||||
<CustomBuild Include="include\Mutils\UpdateChecker.h">
|
<CustomBuild Include="include\Mutils\UpdateChecker.h">
|
||||||
@ -118,7 +121,7 @@
|
|||||||
<PreprocessorDefinitions>WIN32;MUTILS_DLL_EXPORT;_DEBUG;_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;QT_DLL;QT_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;MUTILS_DLL_EXPORT;_DEBUG;_LIB;QT_GUI_LIB;QT_CORE_LIB;QT_THREAD_SUPPORT;QT_DLL;QT_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||||
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
<EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
@ -145,8 +148,9 @@
|
|||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@ -154,7 +158,7 @@
|
|||||||
<OptimizeReferences>true</OptimizeReferences>
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
<AdditionalLibraryDirectories>$(QTDIR)\lib</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>$(QTDIR)\lib</AdditionalLibraryDirectories>
|
||||||
<AdditionalDependencies>QtCore4.lib;QtGui4.lib;Psapi.lib;Sensapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>QtCore4.lib;QtGui4.lib;Psapi.lib;Sensapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">
|
||||||
@ -174,8 +178,10 @@
|
|||||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||||
<FloatingPointModel>Fast</FloatingPointModel>
|
<FloatingPointModel>Fast</FloatingPointModel>
|
||||||
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
<CreateHotpatchableImage>false</CreateHotpatchableImage>
|
||||||
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(ProjectDir)\include;$(QTDIR)\include;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(SolutionDir)\..\Prerequisites\VisualLeakDetector\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<TreatWarningAsError>true</TreatWarningAsError>
|
<TreatWarningAsError>true</TreatWarningAsError>
|
||||||
|
<CompileAsManaged>false</CompileAsManaged>
|
||||||
|
<DebugInformationFormat>None</DebugInformationFormat>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
@ -19,6 +19,12 @@
|
|||||||
<Filter Include="Source Files\Generated">
|
<Filter Include="Source Files\Generated">
|
||||||
<UniqueIdentifier>{458f07b7-5414-4e9c-a599-222196e8d2e8}</UniqueIdentifier>
|
<UniqueIdentifier>{458f07b7-5414-4e9c-a599-222196e8d2e8}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Source Files\3rd Party">
|
||||||
|
<UniqueIdentifier>{d5bcdb46-27a3-4772-86b4-1b30e02a30cc}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Header Files\3rd Party">
|
||||||
|
<UniqueIdentifier>{6261ec8d-8041-495b-bddf-6fe07c11c952}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="src\UpdateChecker.cpp">
|
<ClCompile Include="src\UpdateChecker.cpp">
|
||||||
@ -57,6 +63,9 @@
|
|||||||
<ClCompile Include="src\GUI.cpp">
|
<ClCompile Include="src\GUI.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\3rd_party\strnatcmp\src\strnatcmp.cpp">
|
||||||
|
<Filter>Source Files\3rd Party</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="src\CriticalSection_Win32.h">
|
<ClInclude Include="src\CriticalSection_Win32.h">
|
||||||
@ -98,6 +107,12 @@
|
|||||||
<ClInclude Include="src\Utils_Win32.h">
|
<ClInclude Include="src\Utils_Win32.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\3rd_party\strnatcmp\include\strnatcmp.h">
|
||||||
|
<Filter>Header Files\3rd Party</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\3rd_party\keccak\include\keccak_impl.h">
|
||||||
|
<Filter>Header Files\3rd Party</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="include\Mutils\UpdateChecker.h">
|
<CustomBuild Include="include\Mutils\UpdateChecker.h">
|
||||||
|
@ -88,6 +88,9 @@ namespace MUtils
|
|||||||
MUTILS_API bool remove_file(const QString &fileName);
|
MUTILS_API bool remove_file(const QString &fileName);
|
||||||
MUTILS_API bool remove_directory(const QString &folderPath);
|
MUTILS_API bool remove_directory(const QString &folderPath);
|
||||||
|
|
||||||
|
//String sorting
|
||||||
|
MUTILS_API void natural_string_sort(QStringList &list, const bool bIgnoreCase);
|
||||||
|
|
||||||
//Internal
|
//Internal
|
||||||
namespace Internal
|
namespace Internal
|
||||||
{
|
{
|
||||||
|
@ -56,39 +56,42 @@
|
|||||||
|
|
||||||
namespace MUtils
|
namespace MUtils
|
||||||
{
|
{
|
||||||
// Section from KeccakSponge.h
|
namespace Internal
|
||||||
// needed here, since hashState needs to be explicitly 32-byte aligned and therefore can't be
|
|
||||||
// transformed into a class (in order to forward declarate) like in the other hash wrappers.
|
|
||||||
namespace KeccakImpl
|
|
||||||
{
|
{
|
||||||
#define KeccakPermutationSize 1600
|
// Section from KeccakSponge.h
|
||||||
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
|
// needed here, since hashState needs to be explicitly 32-byte aligned and therefore can't be
|
||||||
#define KeccakMaximumRate 1536
|
// transformed into a class (in order to forward declarate) like in the other hash wrappers.
|
||||||
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8)
|
namespace KeccakImpl
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
|
||||||
#define ALIGN __attribute__ ((aligned(32)))
|
|
||||||
#elif defined(_MSC_VER)
|
|
||||||
#define ALIGN __declspec(align(32))
|
|
||||||
#else
|
|
||||||
#define ALIGN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ALIGN typedef struct spongeStateStruct
|
|
||||||
{
|
{
|
||||||
ALIGN unsigned char state[KeccakPermutationSizeInBytes];
|
#define KeccakPermutationSize 1600
|
||||||
ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes];
|
#define KeccakPermutationSizeInBytes (KeccakPermutationSize/8)
|
||||||
unsigned int rate;
|
#define KeccakMaximumRate 1536
|
||||||
unsigned int capacity;
|
#define KeccakMaximumRateInBytes (KeccakMaximumRate/8)
|
||||||
unsigned int bitsInQueue;
|
|
||||||
unsigned int fixedOutputLength;
|
#if defined(__GNUC__)
|
||||||
int squeezing;
|
#define ALIGN __attribute__ ((aligned(32)))
|
||||||
unsigned int bitsAvailableForSqueezing;
|
#elif defined(_MSC_VER)
|
||||||
|
#define ALIGN __declspec(align(32))
|
||||||
|
#else
|
||||||
|
#define ALIGN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ALIGN typedef struct spongeStateStruct
|
||||||
|
{
|
||||||
|
ALIGN unsigned char state[KeccakPermutationSizeInBytes];
|
||||||
|
ALIGN unsigned char dataQueue[KeccakMaximumRateInBytes];
|
||||||
|
unsigned int rate;
|
||||||
|
unsigned int capacity;
|
||||||
|
unsigned int bitsInQueue;
|
||||||
|
unsigned int fixedOutputLength;
|
||||||
|
int squeezing;
|
||||||
|
unsigned int bitsAvailableForSqueezing;
|
||||||
|
}
|
||||||
|
spongeState;
|
||||||
|
typedef spongeState hashState;
|
||||||
}
|
}
|
||||||
spongeState;
|
// End Section from KeccakSponge.h
|
||||||
typedef spongeState hashState;
|
|
||||||
}
|
}
|
||||||
// End Section from KeccakSponge.h
|
|
||||||
|
|
||||||
class MUTILS_API KeccakHash
|
class MUTILS_API KeccakHash
|
||||||
{
|
{
|
||||||
@ -107,7 +110,7 @@ namespace MUtils
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_initialized;
|
bool m_initialized;
|
||||||
KeccakImpl::hashState *m_state;
|
Internal::KeccakImpl::hashState *m_state;
|
||||||
QByteArray m_hashResult;
|
QByteArray m_hashResult;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
27
src/3rd_party/keccak/LICENSE.txt
vendored
Normal file
27
src/3rd_party/keccak/LICENSE.txt
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
|
||||||
|
|
||||||
|
LICENSE TERMS
|
||||||
|
|
||||||
|
The redistribution and use of this software (with or without changes)
|
||||||
|
is allowed without the payment of fees or royalties provided that:
|
||||||
|
|
||||||
|
1. source code distributions include the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer;
|
||||||
|
|
||||||
|
2. binary distributions include the above copyright notice, this list
|
||||||
|
of conditions and the following disclaimer in their documentation;
|
||||||
|
|
||||||
|
3. the name of the copyright holder is not used to endorse products
|
||||||
|
built using this software without specific written permission.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
|
||||||
|
This software is provided 'as is' with no explicit or implied warranties
|
||||||
|
in respect of its properties, including, but not limited to, correctness
|
||||||
|
and/or fitness for purpose.
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
Issue Date: 20/12/2007
|
||||||
|
Changes for ARM 9/9/2010
|
||||||
|
*/
|
@ -19,6 +19,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
namespace MUtils {
|
namespace MUtils {
|
||||||
|
namespace Internal {
|
||||||
namespace KeccakImpl {
|
namespace KeccakImpl {
|
||||||
|
|
||||||
typedef unsigned char UINT8;
|
typedef unsigned char UINT8;
|
||||||
@ -1997,5 +1998,6 @@ HashReturn Hash(int hashbitlen, const BitSequence *data, DataLength databitlen,
|
|||||||
|
|
||||||
|
|
||||||
} // end of namespace KeccakImpl
|
} // end of namespace KeccakImpl
|
||||||
|
} // end of namespace Internal
|
||||||
} // end of namespace MUtils
|
} // end of namespace MUtils
|
||||||
|
|
40
src/3rd_party/strnatcmp/include/strnatcmp.h
vendored
Normal file
40
src/3rd_party/strnatcmp/include/strnatcmp.h
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
namespace MUtils
|
||||||
|
{
|
||||||
|
namespace Internal
|
||||||
|
{
|
||||||
|
namespace NaturalSort
|
||||||
|
{
|
||||||
|
/* CUSTOMIZATION SECTION
|
||||||
|
*
|
||||||
|
* You can change this typedef, but must then also change the inline
|
||||||
|
* functions in strnatcmp.c */
|
||||||
|
typedef wchar_t nat_char;
|
||||||
|
|
||||||
|
int strnatcmp(nat_char const *a, nat_char const *b);
|
||||||
|
int strnatcasecmp(nat_char const *a, nat_char const *b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
196
src/3rd_party/strnatcmp/readme.htm
vendored
Normal file
196
src/3rd_party/strnatcmp/readme.htm
vendored
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||||
|
<html><head>
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=windows-1252">
|
||||||
|
<title>Natural Order String Comparison</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Natural Order String Comparison</h1>
|
||||||
|
<p>by <a href="http://sourcefrog.net/">Martin Pool</a>
|
||||||
|
|
||||||
|
</p><p>Computer string sorting algorithms generally don't order strings
|
||||||
|
containing numbers in the same way that a human would do. Consider:
|
||||||
|
|
||||||
|
</p><blockquote><pre>rfc1.txt
|
||||||
|
rfc2086.txt
|
||||||
|
rfc822.txt
|
||||||
|
</pre></blockquote>
|
||||||
|
<p>It would be more friendly if the program listed the files as
|
||||||
|
|
||||||
|
</p><blockquote><pre>rfc1.txt
|
||||||
|
rfc822.txt
|
||||||
|
rfc2086.txt
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p>Filenames sort properly if people insert leading zeros, but they
|
||||||
|
don't always do that.
|
||||||
|
|
||||||
|
</p><p>I've written a subroutine that compares strings according to this
|
||||||
|
natural ordering. You can use this routine in your own software, or
|
||||||
|
download a patch to add it to your favourite Unix program.
|
||||||
|
|
||||||
|
|
||||||
|
</p><h2>Sorting</h2>
|
||||||
|
|
||||||
|
<p>Strings are sorted as usual, except that decimal integer substrings
|
||||||
|
are compared on their numeric value. For example,
|
||||||
|
|
||||||
|
</p><blockquote>
|
||||||
|
a < a0 < a1 < a1a < a1b < a2 < a10 < a20
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Strings can contain several number parts:
|
||||||
|
|
||||||
|
</p><blockquote>
|
||||||
|
x2-g8 < x2-y7 < x2-y08 < x8-y8
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
in which case numeric fields are separated by nonnumeric characters.
|
||||||
|
Leading spaces are ignored. This works very well for IP addresses
|
||||||
|
from log files, for example.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Leading zeros are <u>not</u> ignored, which tends to give more
|
||||||
|
reasonable results on decimal fractions.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
1.001 < 1.002 < 1.010 < 1.02 < 1.1 < 1.3
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Some applications may wish to change this by modifying the test
|
||||||
|
that calls <code>isspace</code>.
|
||||||
|
|
||||||
|
|
||||||
|
</p><p>
|
||||||
|
Performance is linear: each character of the string is scanned
|
||||||
|
at most once, and only as many characters as necessary to decide
|
||||||
|
are considered.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><a href="http://sourcefrog.net/projects/natsort/example-out.txt">Longer example of the results</a>
|
||||||
|
|
||||||
|
|
||||||
|
</p><h2>Licensing</h2>
|
||||||
|
|
||||||
|
<p>This software is copyright by Martin Pool, and made available under
|
||||||
|
the same licence as zlib:
|
||||||
|
|
||||||
|
</p><blockquote>
|
||||||
|
<p> This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
</p><p> Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
</p><p> 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
</p><p> 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
</p><p> 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
</p></blockquote>
|
||||||
|
|
||||||
|
<p>This licence applies only to the C implementation. You are free to
|
||||||
|
reimplement the idea fom scratch in any language.
|
||||||
|
|
||||||
|
</p><h2>Related Work</h2>
|
||||||
|
|
||||||
|
|
||||||
|
<p>
|
||||||
|
POSIX sort(1) has the -n option to sort numbers, but this doesn't
|
||||||
|
work if there is a non-numeric prefix.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
GNU ls(1) has the <tt>--sort=version</tt> option, which works
|
||||||
|
the same way.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The PHP scripting language now has a
|
||||||
|
<a href="http://us3.php.net/manual/en/function.strnatcmp.php">strnatcmp</a>
|
||||||
|
function based on this code.
|
||||||
|
The PHP wrapper was done by Andrei Zimievsky.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="http://www.naturalordersort.org/">Stuart
|
||||||
|
Cheshire</a> has a Macintosh <q>system extension</q> to do natural ordering.
|
||||||
|
I indepdendently reinvented the algorithm, but Stuart had it
|
||||||
|
first. I borrowed the term <q>natural sort</q> from him.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a href="http://search.cpan.org/src/EDAVIS/Sort-Versions-1.4/README"><tt>Sort::Versions</tt></a>
|
||||||
|
in Perl. "The code has some special magic to deal with common
|
||||||
|
conventions in program version numbers, like the difference between
|
||||||
|
'decimal' versions (eg perl 5.005) and the Unix kind (eg perl 5.6.1)."
|
||||||
|
|
||||||
|
</p><p><a href="http://www.cpan.org/modules/by-module/Sort/Sort-Naturally-1.01.readme"><tt>Sort::Naturally</tt></a>
|
||||||
|
is also in Perl, by Sean M. Burke. It uses locale-sensitive character classes to sort words and numeric substrings
|
||||||
|
in a way similar to natsort.
|
||||||
|
|
||||||
|
</p><p>
|
||||||
|
Ed Avis wrote <a href="http://membled.com/work/apps/todo/numsort">something similar in Haskell</a>.
|
||||||
|
|
||||||
|
|
||||||
|
</p><p>
|
||||||
|
Pierre-Luc Paour wrote a <a href="http://pierre-luc.paour.9online.fr/NaturalOrderComparator.java"><tt>NaturalOrderComparator</tt>
|
||||||
|
in Java</a>
|
||||||
|
|
||||||
|
</p><p>Kristof Coomans wrote a <a href="http://sourcefrog.net/projects/natsort/natcompare.js">natural sort comparison in Javascript</a></p>
|
||||||
|
|
||||||
|
<p>Alan Davies wrote
|
||||||
|
<a href="http://sourcefrog.net/projects/natsort/natcmp.rb"><tt>natcmp.rb</tt></a>,
|
||||||
|
an implementation in <a href="http://www.ruby-lang.org/">Ruby</a>.
|
||||||
|
|
||||||
|
</p><p><a href="http://sourceforge.net/projects/numacomp">Numacomp</a>
|
||||||
|
- similar thing in Python.
|
||||||
|
|
||||||
|
</p><p><a href="http://code.google.com/p/as3natcompare/">as3natcompare</a>
|
||||||
|
implementation in Flash ActionScript 3.
|
||||||
|
|
||||||
|
</p><h2>Get It!</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="http://sourcefrog.net/projects/natsort/strnatcmp.c">strnatcmp.c</a>,
|
||||||
|
<a href="http://sourcefrog.net/projects/natsort/strnatcmp.h">strnatcmp.h</a> - the algorithm itself
|
||||||
|
|
||||||
|
</li><li><a href="http://sourcefrog.net/projects/natsort/natsort.c">natsort.c</a> - example driver program.
|
||||||
|
(Try <tt>ls -F /proc | natsort</tt>)
|
||||||
|
|
||||||
|
</li><li><a href="http://sourcefrog.net/projects/natsort/textutils.diff">textutils.diff</a> - patch to add
|
||||||
|
natural sort to sort(1) from GNU textutils-2.0; use the new
|
||||||
|
<tt>-N</tt> option.</li>
|
||||||
|
|
||||||
|
<li>Natural ordering is now in PHP4rc2, through the <a href="http://php.net/manual/html/function.strnatcasecmp.html">strnatcasecmp</a>
|
||||||
|
and <a href="http://php.net/manual/html/function.strnatcmp.html">strnatcmp</a>
|
||||||
|
functions.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<h2>To Do</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Comparison of characters is purely numeric, without taking
|
||||||
|
character set or locale into account. So it is only correct for
|
||||||
|
ASCII. This should probably be a separate function because doing
|
||||||
|
the comparisons will probably introduce a dependency on the OS
|
||||||
|
mechanism for finding the locale and comparing characters.
|
||||||
|
|
||||||
|
|
||||||
|
</p><p>
|
||||||
|
It might be good to support multibyte character sets too.
|
||||||
|
|
||||||
|
</p><p>
|
||||||
|
If you fix either of these, please mail me. They should not be
|
||||||
|
very hard.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</p></body></html>
|
214
src/3rd_party/strnatcmp/src/strnatcmp.cpp
vendored
Normal file
214
src/3rd_party/strnatcmp/src/strnatcmp.cpp
vendored
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
/* -*- mode: c; c-file-style: "k&r" -*-
|
||||||
|
|
||||||
|
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
|
||||||
|
Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* partial change history:
|
||||||
|
*
|
||||||
|
* 2004-10-10 mbp: Lift out character type dependencies into macros.
|
||||||
|
*
|
||||||
|
* Eric Sosman pointed out that ctype functions take a parameter whose
|
||||||
|
* value must be that of an unsigned int, even on platforms that have
|
||||||
|
* negative chars in their default char type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2013-08-23: Skip leading zero's for any run of digits, except
|
||||||
|
* when a decimal point was seen immediatley before.
|
||||||
|
* Patch by LoRd_MuldeR <mulder2@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "../include/strnatcmp.h"
|
||||||
|
|
||||||
|
/* These are defined as macros to make it easier to adapt this code to
|
||||||
|
* different characters types or comparison functions. */
|
||||||
|
static inline int nat_isdigit(MUtils::Internal::NaturalSort::nat_char a)
|
||||||
|
{
|
||||||
|
return iswdigit(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int nat_isspace(MUtils::Internal::NaturalSort::nat_char a)
|
||||||
|
{
|
||||||
|
return iswspace(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline MUtils::Internal::NaturalSort::nat_char nat_isdecpoint(MUtils::Internal::NaturalSort::nat_char a)
|
||||||
|
{
|
||||||
|
return (a == L'.') || (a == L',');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline MUtils::Internal::NaturalSort::nat_char nat_toupper(MUtils::Internal::NaturalSort::nat_char a)
|
||||||
|
{
|
||||||
|
return towupper(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_right(MUtils::Internal::NaturalSort::nat_char const *a, MUtils::Internal::NaturalSort::nat_char const *b)
|
||||||
|
{
|
||||||
|
int bias = 0;
|
||||||
|
|
||||||
|
/* The longest run of digits wins. That aside, the greatest
|
||||||
|
value wins, but we can't know that it will until we've scanned
|
||||||
|
both numbers to know that they have the same magnitude, so we
|
||||||
|
remember it in BIAS. */
|
||||||
|
for (;; a++, b++)
|
||||||
|
{
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return bias;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b)
|
||||||
|
{
|
||||||
|
if (!bias)
|
||||||
|
bias = -1;
|
||||||
|
}
|
||||||
|
else if (*a > *b)
|
||||||
|
{
|
||||||
|
if (!bias)
|
||||||
|
bias = +1;
|
||||||
|
}
|
||||||
|
else if (!*a && !*b)
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_left(MUtils::Internal::NaturalSort::nat_char const *a, MUtils::Internal::NaturalSort::nat_char const *b)
|
||||||
|
{
|
||||||
|
/* Compare two left-aligned numbers: the first to have a
|
||||||
|
different value wins. */
|
||||||
|
for (;; a++, b++)
|
||||||
|
{
|
||||||
|
if (!nat_isdigit(*a) && !nat_isdigit(*b))
|
||||||
|
return 0;
|
||||||
|
else if (!nat_isdigit(*a))
|
||||||
|
return -1;
|
||||||
|
else if (!nat_isdigit(*b))
|
||||||
|
return +1;
|
||||||
|
else if (*a < *b)
|
||||||
|
return -1;
|
||||||
|
else if (*a > *b)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int strnatcmp0(MUtils::Internal::NaturalSort::nat_char const *a, MUtils::Internal::NaturalSort::nat_char const *b, const bool fold_case)
|
||||||
|
{
|
||||||
|
int ai, bi;
|
||||||
|
MUtils::Internal::NaturalSort::nat_char ca, cb;
|
||||||
|
int result;
|
||||||
|
bool fractional;
|
||||||
|
int sa, sb;
|
||||||
|
|
||||||
|
assert(a && b);
|
||||||
|
ai = bi = 0;
|
||||||
|
fractional = false;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ca = a[ai]; cb = b[bi];
|
||||||
|
|
||||||
|
/* skip over leading spaces or zeros */
|
||||||
|
while (nat_isspace(ca))
|
||||||
|
ca = a[++ai];
|
||||||
|
|
||||||
|
while (nat_isspace(cb))
|
||||||
|
cb = b[++bi];
|
||||||
|
|
||||||
|
/* process run of digits */
|
||||||
|
if (nat_isdigit(ca) && nat_isdigit(cb))
|
||||||
|
{
|
||||||
|
sa = sb = 0;
|
||||||
|
|
||||||
|
if(!fractional)
|
||||||
|
{
|
||||||
|
while (ca == L'0')
|
||||||
|
{
|
||||||
|
ca = a[++ai]; sa++;
|
||||||
|
}
|
||||||
|
while (cb == L'0')
|
||||||
|
{
|
||||||
|
cb = b[++bi]; sb++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fractional)
|
||||||
|
{
|
||||||
|
if ((result = compare_left(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((result = compare_right(a+ai, b+bi)) != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* on tie, the string with the longer leading zero's sequence wins */
|
||||||
|
if(sa < sb)
|
||||||
|
return -1;
|
||||||
|
else if(sa > sb)
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ca && !cb)
|
||||||
|
{
|
||||||
|
/* The strings compare the same. Perhaps the caller
|
||||||
|
will want to call strcmp to break the tie. */
|
||||||
|
return (fold_case) ? _wcsicmp(a, b) : wcscmp(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fold_case)
|
||||||
|
{
|
||||||
|
ca = nat_toupper(ca);
|
||||||
|
cb = nat_toupper(cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ca < cb)
|
||||||
|
return -1;
|
||||||
|
else if (ca > cb)
|
||||||
|
return +1;
|
||||||
|
|
||||||
|
/* skipp leading zero's, unless previously seen char was a decimal point */
|
||||||
|
fractional = nat_isdecpoint(ca) && nat_isdecpoint(cb);
|
||||||
|
|
||||||
|
++ai; ++bi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int MUtils::Internal::NaturalSort::strnatcmp(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
return strnatcmp0(a, b, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compare, recognizing numeric string and ignoring case. */
|
||||||
|
int MUtils::Internal::NaturalSort::strnatcasecmp(nat_char const *a, nat_char const *b)
|
||||||
|
{
|
||||||
|
return strnatcmp0(a, b, true);
|
||||||
|
}
|
@ -26,7 +26,10 @@
|
|||||||
//MUtils
|
//MUtils
|
||||||
#include <MUtils/Global.h>
|
#include <MUtils/Global.h>
|
||||||
#include <MUtils/OSSupport.h>
|
#include <MUtils/OSSupport.h>
|
||||||
|
|
||||||
|
//Internal
|
||||||
#include "DirLocker.h"
|
#include "DirLocker.h"
|
||||||
|
#include "3rd_party/strnatcmp/include/strnatcmp.h"
|
||||||
|
|
||||||
//Qt
|
//Qt
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -301,6 +304,25 @@ void MUtils::init_process(QProcess &process, const QString &wokringDir, const bo
|
|||||||
process.setProcessEnvironment(env);
|
process.setProcessEnvironment(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// NATURAL ORDER STRING COMPARISON
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static bool natural_string_sort_helper(const QString &str1, const QString &str2)
|
||||||
|
{
|
||||||
|
return (MUtils::Internal::NaturalSort::strnatcmp(MUTILS_WCHR(str1), MUTILS_WCHR(str2)) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool natural_string_sort_helper_fold_case(const QString &str1, const QString &str2)
|
||||||
|
{
|
||||||
|
return (MUtils::Internal::NaturalSort::strnatcasecmp(MUTILS_WCHR(str1), MUTILS_WCHR(str2)) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MUtils::natural_string_sort(QStringList &list, const bool bIgnoreCase)
|
||||||
|
{
|
||||||
|
qSort(list.begin(), list.end(), bIgnoreCase ? natural_string_sort_helper_fold_case : natural_string_sort_helper);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// SELF-TEST
|
// SELF-TEST
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
** **
|
** **
|
||||||
** MUtils::KeccakHash, an API wrapper bringing the optimized implementation of **
|
** QKeccakHash, an API wrapper bringing the optimized implementation of **
|
||||||
** Keccak (http://keccak.noekeon.org/) to Qt. **
|
** Keccak (http://keccak.noekeon.org/) to Qt. **
|
||||||
** Copyright (C) 2013 Emanuel Eichhammer **
|
** Copyright (C) 2013 Emanuel Eichhammer **
|
||||||
** **
|
** **
|
||||||
@ -47,17 +47,17 @@
|
|||||||
#include <MUtils/KeccakHash.h>
|
#include <MUtils/KeccakHash.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "3rd_party/keccak_impl.h"
|
#include "3rd_party/keccak/include/keccak_impl.h"
|
||||||
|
|
||||||
MUtils::KeccakHash::KeccakHash()
|
MUtils::KeccakHash::KeccakHash()
|
||||||
{
|
{
|
||||||
m_initialized = false;
|
m_initialized = false;
|
||||||
m_state = (MUtils::KeccakImpl::hashState*) _aligned_malloc(sizeof(MUtils::KeccakImpl::hashState), 32);
|
m_state = (MUtils::Internal::KeccakImpl::hashState*) _aligned_malloc(sizeof(MUtils::Internal::KeccakImpl::hashState), 32);
|
||||||
if(!m_state)
|
if(!m_state)
|
||||||
{
|
{
|
||||||
throw "[MUtils::KeccakHash] Error: _aligned_malloc() has failed, probably out of heap space!";
|
throw "[MUtils::KeccakHash] Error: _aligned_malloc() has failed, probably out of heap space!";
|
||||||
}
|
}
|
||||||
memset(m_state, 0, sizeof(MUtils::KeccakImpl::hashState));
|
memset(m_state, 0, sizeof(MUtils::Internal::KeccakImpl::hashState));
|
||||||
m_hashResult.clear();
|
m_hashResult.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ bool MUtils::KeccakHash::init(HashBits hashBits)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_hashResult.clear();
|
m_hashResult.clear();
|
||||||
memset(m_state, 0, sizeof(MUtils::KeccakImpl::hashState));
|
memset(m_state, 0, sizeof(MUtils::Internal::KeccakImpl::hashState));
|
||||||
int hashBitLength = 0;
|
int hashBitLength = 0;
|
||||||
|
|
||||||
switch (hashBits)
|
switch (hashBits)
|
||||||
@ -93,7 +93,7 @@ bool MUtils::KeccakHash::init(HashBits hashBits)
|
|||||||
default: throw "Invalid hash length!!";
|
default: throw "Invalid hash length!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MUtils::KeccakImpl::Init(m_state, hashBitLength) != MUtils::KeccakImpl::SUCCESS)
|
if(MUtils::Internal::KeccakImpl::Init(m_state, hashBitLength) != MUtils::Internal::KeccakImpl::SUCCESS)
|
||||||
{
|
{
|
||||||
qWarning("KeccakImpl::Init() has failed unexpectedly!");
|
qWarning("KeccakImpl::Init() has failed unexpectedly!");
|
||||||
return false;
|
return false;
|
||||||
@ -118,7 +118,7 @@ bool MUtils::KeccakHash::addData(const char *data, int size)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MUtils::KeccakImpl::Update(m_state, (MUtils::KeccakImpl::BitSequence*)data, size*8) != MUtils::KeccakImpl::SUCCESS)
|
if(MUtils::Internal::KeccakImpl::Update(m_state, (MUtils::Internal::KeccakImpl::BitSequence*)data, size*8) != MUtils::Internal::KeccakImpl::SUCCESS)
|
||||||
{
|
{
|
||||||
qWarning("KeccakImpl::Update() has failed unexpectedly!");
|
qWarning("KeccakImpl::Update() has failed unexpectedly!");
|
||||||
m_hashResult.clear();
|
m_hashResult.clear();
|
||||||
@ -138,7 +138,7 @@ const QByteArray &MUtils::KeccakHash::finalize()
|
|||||||
return m_hashResult;
|
return m_hashResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(MUtils::KeccakImpl::Final(m_state, (MUtils::KeccakImpl::BitSequence*)m_hashResult.data()) != MUtils::KeccakImpl::SUCCESS)
|
if(MUtils::Internal::KeccakImpl::Final(m_state, (MUtils::Internal::KeccakImpl::BitSequence*)m_hashResult.data()) != MUtils::Internal::KeccakImpl::SUCCESS)
|
||||||
{
|
{
|
||||||
qWarning("KeccakImpl::Final() has failed unexpectedly!");
|
qWarning("KeccakImpl::Final() has failed unexpectedly!");
|
||||||
m_hashResult.clear();
|
m_hashResult.clear();
|
||||||
|
@ -94,7 +94,7 @@ static int startup_helper(int &argc, char **argv, MUtils::Startup::main_function
|
|||||||
int MUtils::Startup::startup(int &argc, char **argv, main_function_t *const entry_point)
|
int MUtils::Startup::startup(int &argc, char **argv, main_function_t *const entry_point)
|
||||||
{
|
{
|
||||||
int iResult = -1;
|
int iResult = -1;
|
||||||
#if(MUTILS_DEBUG)
|
#if 1||(MUTILS_DEBUG)
|
||||||
iResult = startup_main(argc, argv, entry_point);
|
iResult = startup_main(argc, argv, entry_point);
|
||||||
#else //MUTILS_DEBUG
|
#else //MUTILS_DEBUG
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
//Internal
|
//Internal
|
||||||
#include <MUtils/Global.h>
|
#include <MUtils/Global.h>
|
||||||
#include <MUtils/Exception.h>
|
#include <MUtils/Exception.h>
|
||||||
|
#include <MUtils/OSSupport.h>
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
Loading…
Reference in New Issue
Block a user