Compare commits

...

16 Commits

Author SHA1 Message Date
052fa7f4d1 chore: update build script.
- update CMake build script to make install statement is more legal.
- add Windows-only build script for creating CMake used package and MSVC used package on Windows.
- documentation will be added in the next commit.
2024-07-22 13:56:00 +08:00
9e5bd370c4 doc: add documentation for ConfigManager 2024-07-18 09:28:10 +08:00
94386c93aa doc: finish documentation of StringHelper 2024-07-17 14:18:54 +08:00
b13bb445e4 doc: add documentation for ConsoleHelper 2024-07-16 10:41:09 +08:00
81fe72c425 chore: add Natvis in MSVC CMake build.
- add Natvis in MSVC CMake build to let me can see the data encoded with YYCC::yycc_char8_t.
2024-07-15 22:47:49 +08:00
b912be082c doc: add documentation for COMHelper 2024-07-15 13:47:14 +08:00
9f47d0fe24 doc: update documentation for ParserHelper 2024-07-14 11:19:37 +08:00
cc689ce8bb doc: update README
- add MIT license
- update README. remove WIP mark.
- move some content from README to documentation.
2024-07-13 22:50:37 +08:00
1ccea1290e doc: add documentation for win fct helper
- add documentation for win fct helper
- add new macro YYCC_U8_CHAR for casting ordinary char to yycc utf8 char.
- add documentation for new added YYCC_U8_CHAR.
2024-07-13 12:58:49 +08:00
ed549592dd doc: update documentation for FsPathPatch 2024-07-12 09:44:56 +08:00
1c2007928d doc: update documentation for IO helper.
- update IO helper ducumentation.
- fix a latent Linux compile error in IO helper.
2024-07-11 09:59:50 +08:00
a6c543c1b5 doc: finish dialog helper documentation 2024-07-10 09:24:39 +08:00
942e4ff8eb feat: add convertion functions between utf8 and code page string 2024-07-09 21:02:26 +08:00
9a18233723 doc: update document for exception helper 2024-07-08 10:44:09 +08:00
11b2185bb4 chore: update documentation build script 2024-07-08 08:54:49 +08:00
d27a66e770 fix: fix ConfigManager::StringSetting issues
- use yycc_u8string_view in default value and Set function instead of const yycc_char8_t*
- fix value check error in Set function.
2024-07-07 21:33:42 +08:00
33 changed files with 1145 additions and 157 deletions

View File

@ -8,19 +8,18 @@ project(YYCC
option(YYCC_BUILD_TESTBENCH "Build testbench of YYCCommonplace." OFF) option(YYCC_BUILD_TESTBENCH "Build testbench of YYCCommonplace." OFF)
option(YYCC_BUILD_DOC "Build document of YYCCommonplace." OFF) option(YYCC_BUILD_DOC "Build document of YYCCommonplace." OFF)
# Detect MSVC IDE environment. # Setup install path from CMake provided install path for convenient use.
# If we in it, we should add configuration and build type in install path. include(GNUInstallDirs)
if (CMAKE_GENERATOR MATCHES "Visual Studio") set(YYCC_INSTALL_INCLUDE_PATH ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH
# Do Visual Studio specific "Public header install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
set(YYCC_INSTALL_PATH_LIB lib/${CMAKE_VS_PLATFORM_NAME}/$<CONFIG>) set(YYCC_INSTALL_LIB_PATH ${CMAKE_INSTALL_LIBDIR} CACHE PATH
set(YYCC_INSTALL_PATH_BIN bin/${CMAKE_VS_PLATFORM_NAME}) "Library install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
else() set(YYCC_INSTALL_BIN_PATH ${CMAKE_INSTALL_BINDIR} CACHE PATH
# Other stuff "Binary install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
set(YYCC_INSTALL_PATH_LIB lib) set(YYCC_INSTALL_DOC_PATH ${CMAKE_INSTALL_DOCDIR} CACHE PATH
set(YYCC_INSTALL_PATH_BIN bin) "Non-arch doc install path relative to CMAKE_INSTALL_PREFIX unless set to an absolute path.")
endif()
# Import 2 build targets # Import 3 build targets
add_subdirectory(src) add_subdirectory(src)
if (YYCC_BUILD_TESTBENCH) if (YYCC_BUILD_TESTBENCH)
add_subdirectory(testbench) add_subdirectory(testbench)
@ -29,12 +28,12 @@ if (YYCC_BUILD_DOC)
add_subdirectory(doc) add_subdirectory(doc)
endif () endif ()
# Install project package infos # Install target and package
# Package target # Install target
install(EXPORT YYCCommonplaceTargets install(EXPORT YYCCommonplaceTargets
FILE YYCCommonplaceTargets.cmake FILE YYCCommonplaceTargets.cmake
NAMESPACE YYCC:: NAMESPACE YYCC::
DESTINATION lib/cmake/YYCCommonplace DESTINATION ${YYCC_INSTALL_LIB_PATH}/cmake/YYCCommonplace
) )
# Package configuration file # Package configuration file
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
@ -46,14 +45,14 @@ write_basic_package_version_file(
configure_package_config_file( configure_package_config_file(
${CMAKE_CURRENT_LIST_DIR}/cmake/YYCCommonplaceConfig.cmake.in ${CMAKE_CURRENT_LIST_DIR}/cmake/YYCCommonplaceConfig.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfig.cmake"
INSTALL_DESTINATION lib/cmake/YYCCommonplace INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/YYCCommonplace
) )
# Copy to install destination # Copy package files to install destination
install( install(
FILES FILES
"${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/YYCCommonplaceConfigVersion.cmake"
DESTINATION DESTINATION
lib/cmake/YYCCommonplace ${CMAKE_INSTALL_LIBDIR}/cmake/YYCCommonplace
) )

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2024-2024 yyc12345
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.

View File

@ -1,9 +1,16 @@
# YYC Commonplace # YYC Commonplace
During the development of a few projects, I gradually understand how Windows make the compromise with the code written by its old developers, and what is developer wanted in contemporary C++ standard library under Windows environment. So I create this static library for all of my C++ project, After this, I do not need to write these duplicated code in each project. I can use a clear and easy way to manage these codes. I can easily fix issues found in project using this library by updating a single project, rather than fixing these duplicated code in each project one by one because all of them share the same implementations. YYC Commonplace, or YYCCommonplace (abbr. YYCC) is a static library specifically resolving my requirements in C++ and Windows scope.
This project mainly is served for my personal use. But I would be honored if you would like to use this in your project. Almost of my projects, except some critical projects (they will copy this project implementations into their own project scope to eliminate non-common library dependency), will gradually adapt to this project and drop their own individual implementations. ## Usage
This project includes Visual Studio project file and CMake support at the same time. So that at least I can use one of them freely. For more usage about this library, please build documentation of this project via Doxygen and read it.
**WIP. Do not use it now.** And I also highly recommend that you read documentation first before writing with this library.
## Build
This project require at least CMake 3.23 to build. We suggest that you only use stable version (tagged commit). The latest commit may still work in progress and not stable.
For Windows builing, you can browse GitHub action script to have a preview. It actually is a simple calling to script file.
For other platforms building (e.g. Linux), you can following common builing way of CMake project.

View File

@ -1,2 +1,7 @@
# Add the targets file
include("${CMAKE_CURRENT_LIST_DIR}/YYCCommonplaceTargets.cmake") @PACKAGE_INIT@
# Include targets file
include("${CMAKE_CURRENT_LIST_DIR}/YYCCommonplaceTargets.cmake")
check_required_components(YYCCommonplace)

View File

@ -4,3 +4,15 @@ configure_file(
${CMAKE_CURRENT_BINARY_DIR}/Doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
@ONLY @ONLY
) )
# Add custom target
add_custom_target (YYCCDocumentation
doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating documentation" VERBATIM
)
# Install built documentation
install (DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
DESTINATION ${YYCC_INSTALL_DOC_PATH}
)

33
doc/src/com_helper.dox Normal file
View File

@ -0,0 +1,33 @@
/**
\page com_helper COM Helper
This namespace is Windows specific.
It will be invisible on other platforms.
This namespace is used by internal functions as intended.
They should not be used outside of this library.
But if you compel to use them, it is also okey.
\section com_helper__memory_safe_ptr Memory Safe Pointer Types
This namespace also provided various memory-safe types for interacting with COM functions.
Although Microsoft also has similar smart pointer called \c CComPtr.
But this library is eager to hide all Microsoft-related functions calling.
Using \c CComPtr is not corresponding with the philosophy of this library.
So these standard library based smart pointer types were created.
\section com_helper__com_guard COM Guard
This namespace contain a COM Guard which make sure COM was initialized in current module when loading current module.
It is essential because all calling to COM functions should be under the premise that COM has been initialized.
This guard also will uninitialize COM when unloading this module.
There is only an exposed function called YYCC::COMHelper::IsInitialized for user calling.
This function will check whether COM environment is initialized.
If you want YYCC automatically initialize COM environment for you,
you must call this function in your program at least one time.
Otherwise COM Guard code may be unavailable,
because compiler may think they are not essential code and drop them.
*/

View File

@ -2,4 +2,119 @@
\page config_manager Universal Config Manager \page config_manager Universal Config Manager
Universal config manager give programmer an universal way to manage its program settings.
There is an example about how to use universal config manager.
In following content, we will describe it in detail.
\code
class TestConfigManager {
public:
enum class TestEnum : int8_t {
Test1, Test2, Test3
};
TestConfigManager() :
m_IntSetting(YYCC_U8("int-setting"), INT32_C(0)),
m_StringSetting(YYCC_U8("string-setting"), YYCC_U8("")),
m_FloatSetting(YYCC_U8("float-setting"), 0.0f, YYCC::ConfigManager::ConstraintPresets::GetNumberRangeConstraint<float>(-1.0f, 1.0f)),
m_EnumSetting(YYCC_U8("enum-setting"), TestEnum::Test1),
m_CoreManager(YYCC_U8("test.cfg"), UINT64_C(0), {
&m_IntSetting, &m_StringSetting, &m_FloatSetting, &m_EnumSetting
})
{}
~TestConfigManager() {}
YYCC::ConfigManager::NumberSetting<int32_t> m_IntSetting;
YYCC::ConfigManager::StringSetting m_StringSetting;
YYCC::ConfigManager::NumberSetting<float> m_FloatSetting;
YYCC::ConfigManager::NumberSetting<TestEnum> m_EnumSetting;
YYCC::ConfigManager::CoreManager m_CoreManager;
};
// init cfg manager
TestConfigManager test;
// load string
test.m_CoreManager.Load()
// get string value
auto val = test.m_StringSetting.Get();
\endcode
\section config_manager__setting Setting
Setting can be seen as the leaf of the config tree.
Each setting describe a single configuration entry.
\subsection config_manager__setting__presets Setting Presets
We currently provide 2 setting preset classes which you can directly use.
\li YYCC::ConfigManager::NumberSetting: The setting storing a number inside.
It is a template class. Support all arithmetic and enum types (integral, floating point, bool, enum).
\li YYCC::ConfigManager::StringSetting: The setting storing a string inside.
When constructing these settings,
you need to provide its unique name which will be used when saving to file or reading from file.
Also you need to provide a default value for it.
It will be used when fail to read file or initializing itself.
Optionally, you can assign a constraint to it which we will introduce in following section.
\subsection config_manager__setting__custom Custom Setting
In most cases, the combination use of setting presets and constraints introduced in following is enough.
However, if you still are urge to create your personal setting,
please inherit YYCC::ConfigManager::AbstractSetting and implement essential class functions.
For the class functions you need to implement,
please refer to our setting presets, YYCC::ConfigManager::NumberSetting and YYCC::ConfigManager::StringSetting.
\section config_manager__constraint Constraint
Constraint can be applied to specific setting instance,
and limit its value to specific values,
such as minimum maximum value, specific string format and etc.
\subsection config_manager__constraint__presets Constraint Presets
YYCC::ConfigManager provide some constraint presets in YYCC::ConfigManager::Constraints namespace.
All functions inside this namespace will return a YYCC::ConfigManager::Constraint instance,
and you can directly assign it to the constructor of setting.
Currently there is only one constraint preset:
\li YYCC::ConfigManager::Constraints::GetNumberRangeConstraint: Constrain the number value in minimum maximum value range (inclusive).
\subsection config_manager__constraint__custom Custom Constraint
For creating your personal constraint,
you need to create YYCC::ConfigManager::Constraint instance manually.
First you need decide the template argument of YYCC::ConfigManager::Constraint.
The type you assigned to template argument always is
the same type which is accepted by the setting this constraint will be applied to.
Second, you need assign class member of YYCC::ConfigManager::Constraint.
Currently there is only one class member.
It is a function pointer called when correcting value.
See our constraint presets for more infomation about how to write it.
\section config_manager__core_manager Core Manager
YYCC::ConfigManager::CoreManager manage a collection of settings.
And have responsibility to reading and writing config file.
We highly suggest that you create a personal config manager class like example does.
Then put essential settings and core manager inside it.
Please note you must place core manager after all settings.
Because the order of C++ initializing its class member is the order you declared them.
The constructor of core manager need the pointer to all it managed settings,
so it must be initialized after initializing all settings.
When initializing core manager, you need assign config file path first.
Then you need specify a version number.
Version number will be used when reading config file.
If the version of config file is higher than your given number,
core manager will assume you are trying to read a config file created by a higher version program.
Core manager will reject reading and use default value for all settings.
Otherwise, core manager will try to read config file and do proper migration if possible.
The last argument is an initializer list which contain the \b pointer to all settings this manager managed.
*/ */

179
doc/src/console_helper.dox Normal file
View File

@ -0,0 +1,179 @@
/**
\page console_helper Console Helper
This helper provide console related stuff.
This helper includes 2 parts.
First part is console color.
It was constituted by a bunch of macros.
The second part is universal console IO function because Windows is lacking in UTF8 console IO.
All of these parts will be introduced in following content.
\section console_helper__color Console Color
YYCC::ConsoleHelper provide a bunch of macros which can allow you output colorful text in terminal.
Supported color is limited in 16 colors,
because these color is implemented by ASCII Escape Code: https://en.wikipedia.org/wiki/ANSI_escape_code .
So if your terminal do not support this, such as default Windows terminal, or teletypewriter,
you will see some unrecognised characters surrounding with your output.
That's ASCII Escape Code.
\subsection console_helper__color__enable_win_color Enable Color in Windows Console
As we introduced in above,
you may know Windows console does not support ASCII Escape Code color in default.
However YYCC::ConsoleHelper::EnableColorfulConsole can fix this issue.
YYCC::ConsoleHelper::EnableColorfulConsole will forcely enable ASCII Escape Code support in Windows console if possible.
Thus you can write colorful text in Windows console freely.
We suggest you to call this function at the beginning of program.
Considering most Linux console supports ASCII Escape Code very well,
this function does nothing in non-Windows platform.
So it is not essential that brack this function calling with Windows-only \#if.
\subsection console_helper__color__common Common Usage
For common scenarios, you can use macro like this:
\code
YYCC::ConsoleHelper::WriteLine(YYCC_U8(YYCC_COLOR_LIGHT_RED("Light Red Text")));
YYCC::ConsoleHelper::WriteLine(YYCC_U8("I am " YYCC_COLOR_LIGHT_RED("Light Red")));
\endcode
In first line, it will make <TT>"Light Red Text"</TT> to be shown in light red color.
And for second line, it will make <TT>"Light Red"</TT> to be shown in light red color,
but <TT>"I am "</TT> will keep default console font color.
You also may notice this macro is used with YYCC_U8 macro.
Because YYCC::ConsoleHelper::WriteLine only accept UTF8 argument.
So please note if you use console color macro with YYCC_U8,
please make YYCC_U8 always is located the outside.
Otherwise, YYCC_U8 will fail to make the whole become UTF8 stirng as we introduced in \ref library_encoding.
Because console color macro is implemented by string literal concatenation internally.
YYCC_COLOR_LIGHT_RED is a member in YYCC_COLOR macro family.
YYCC_COLOR macro family has 16 members for 16 different colors:
\li YYCC_COLOR_BLACK
\li YYCC_COLOR_RED
\li YYCC_COLOR_GREEN
\li YYCC_COLOR_YELLOW
\li YYCC_COLOR_BLUE
\li YYCC_COLOR_MAGENTA
\li YYCC_COLOR_CYAN
\li YYCC_COLOR_WHITE
\li YYCC_COLOR_LIGHT_BLACK
\li YYCC_COLOR_LIGHT_RED
\li YYCC_COLOR_LIGHT_GREEN
\li YYCC_COLOR_LIGHT_YELLOW
\li YYCC_COLOR_LIGHT_BLUE
\li YYCC_COLOR_LIGHT_MAGENTA
\li YYCC_COLOR_LIGHT_CYAN
\li YYCC_COLOR_LIGHT_WHITE
\subsection console_helper__color__embedded Embedded Usgae
In some cases, you want change console at some time point and reset it in another time point.
You can use color macros like following example:
\code
YYCC::ConsoleHelper::WriteLine(YYCC_U8(YYCC_COLORHDR_LIGHT_BLUE));
// Write as much as you liked
YYCC::ConsoleHelper::WriteLine(YYCC_U8("some string"));
YYCC::ConsoleHelper::WriteLine(YYCC_U8("another string"));
YYCC::ConsoleHelper::WriteLine(YYCC_U8(YYCC_COLORTAIL));
\endcode
At first line, we output YYCC_COLORHDR_LIGHT_BLUE which is in YYCC_COLORHDR macro family.
It is colorful text ASCII Escape Code head.
It will make all following output become light blue color,
until the last line we output YYCC_COLORTAIL to reset console color to original color.
Same as YYCC_COLOR macro family,
YYCC_COLORHDR macro family also has 16 members for 16 different colors:
\li YYCC_COLORHDR_BLACK
\li YYCC_COLORHDR_RED
\li YYCC_COLORHDR_GREEN
\li YYCC_COLORHDR_YELLOW
\li YYCC_COLORHDR_BLUE
\li YYCC_COLORHDR_MAGENTA
\li YYCC_COLORHDR_CYAN
\li YYCC_COLORHDR_WHITE
\li YYCC_COLORHDR_LIGHT_BLACK
\li YYCC_COLORHDR_LIGHT_RED
\li YYCC_COLORHDR_LIGHT_GREEN
\li YYCC_COLORHDR_LIGHT_YELLOW
\li YYCC_COLORHDR_LIGHT_BLUE
\li YYCC_COLORHDR_LIGHT_MAGENTA
\li YYCC_COLORHDR_LIGHT_CYAN
\li YYCC_COLORHDR_LIGHT_WHITE
However YYCC_COLORTAIL is YYCC_COLORTAIL.
There is no other variant for different colors.
Because all tail of colorful ASCII Escape Code is same.
\section console_helper__universal_io Universal IO Function
\subsection console_helper__universal_io__why Why?
Windows console doesn't support UTF8 very well.
The standard input output functions can not work properly with UTF8 on Windows.
So we create this namespace and provide various console-related functions
to patch Windows console and let it more like the console in other platforms.
The function provided in this function can be called in any platforms.
In Windows, the implementation will use Windows native function,
and in other platform, the implementation will redirect request to standard C function like \c std::fputs and etc.
So the programmer do not need to be worried about which function should they use,
and don't need to use macro to use different IO function in different platforms.
It is just enough that fully use the functions provided in this namespace.
All IO functions this namespace provided are UTF8-based.
It also means that input output string should always be UTF8 encoded.
\subsection console_helper__universal_io__input Input Functions
Please note that EOL will automatically converted into LF on Windows platform, not CRLF.
This action actually is removing all CR chars in result string.
This behavior affect nothing in most cases but it still is possible break something in some special case.
Due to implementation, if you decide to use this function,
you should give up using any other function to read stdin stream,
such as \c std::gets() and \c std::cin.
Because this function may read chars which is more than needed.
These extra chars will be stored in this function and can be used next calling.
But these chars can not be visited by stdin again.
This behavior may cause bug.
So if you decide using this function, stick on it and do not change.
Due to implementation, this function do not support hot switch of stdin.
It means that stdin can be redirected before first calling of this function,
but it should not be redirected during program running.
The reason is the same one introduced above.
\subsection console_helper__universal_io__output Output Functions
In current implementation, EOL will not be converted automatically to CRLF.
This is different with other stream read functions provided in this namespace.
Comparing with other stream read functions provided in this namespace,
stream write function support hot switch of stdout and stderr.
Because they do not have internal buffer storing something.
In this namespace, there are various stream write function.
There is a list telling you how to choose one from them for using:
\li Functions with leading "Err" will write data into stderr,
otherwise they will write data into stdout.
\li Functions with embedded "Format" are output functions with format feature
like \c std::fprintf(), otherwise the functions with embedded "Write" will
only write plain string like \c std::fputs().
\li Functions with trailing "Line" will write extra EOL to break current line.
This is commonly used, otherwise functions will only write the text provided by arguments,
without adding something.
*/

View File

@ -32,7 +32,7 @@ YYCC::DialogHelper::FileDialog::SetOwner will set owner of this dialog.
It accepts a Microsoft defined \c HWND as argument which should be familiar with Windows programmer. It accepts a Microsoft defined \c HWND as argument which should be familiar with Windows programmer.
If you pass \c NULL to it or skip calling this function, it indicate that there is no owner of this dialog. If you pass \c NULL to it or skip calling this function, it indicate that there is no owner of this dialog.
<I> <I>
I don't what whill happend if there is no owner for it. I don't what will happen if there is no owner for it.
But it would be better to have an owner if possible. But it would be better to have an owner if possible.
</I> </I>
@ -73,6 +73,95 @@ The directory we meeting in the first launch is system defined.
\section dialog_helper__file_filters Configure File Filters \section dialog_helper__file_filters Configure File Filters
File filters is a drop down list represented in file dialog which allow user filter files by their extensions.
It is beneficial to let user get the file which they want in a directory including massive different files.
<B>For file dialog picking a directory,</B> you can skip this step.
Because the file dialog picking directory does not have file filter drop down box.
Directory can not be filtered.
YYCC::DialogHelper::FileFilters takes responsibility for this feature:
\code
auto& filters = params.ConfigreFileTypes();
filters.Add(YYCC_U8("Microsoft Word (*.docx; *.doc)"), { YYCC_U8("*.docx"), YYCC_U8("*.doc") });
filters.Add(YYCC_U8("Microsoft Excel (*.xlsx; *.xls)"), { YYCC_U8("*.xlsx"), YYCC_U8("*.xls") });
filters.Add(YYCC_U8("Microsoft PowerPoint (*.pptx; *.ppt)"), { YYCC_U8("*.pptx"), YYCC_U8("*.ppt") });
filters.Add(YYCC_U8("Text File (*.txt)"), { YYCC_U8("*.txt") });
filters.Add(YYCC_U8("All Files (*.*)"), { YYCC_U8("*.*") });
params.SetDefaultFileTypeIndex(0u);
\endcode
\subsection dialog_helper__file_filters__setup File Filters
We don't need to initialize YYCC::DialogHelper::FileFilters by ourselves.
Oppositely, we fetch it from YYCC::DialogHelper::FileDialog instance by calling YYCC::DialogHelper::FileDialog::ConfigreFileTypes.
After fetching, we can call YYCC::DialogHelper::FileFilters::Add to add a filter pair for file filters.
The first argument is the display text which user will see in file filter drop down box.
The second argument is a \c std::initializer_list.
Every items are Windows used wildcard string instructing which file should be shown in file dialog.
It is okey to use multiple wildcard string in list.
This is suit for those file types involving multiple file extensions, such as the old and new file types of Microsoft Office as we illustracted.
Empty list not allowed
YYCC::DialogHelper::FileFilters::Add also will return a bool to indicate the success of this adding.
It should at least has one file filter in file dialog.
I don't know the consequence if you don't provide any file filter.
\subsection dialog_helper__file_filters__default_filter Default File Type
YYCC::DialogHelper::FileDialog::SetDefaultFileTypeIndex will set the default selected file filter of this dialog.
It accepts an index pointing to the file filter which you want to show in default for this file dialog.
The index of file filters is the order where you call YYCC::DialogHelper::FileFilters::Add above.
If you pass \c NULL to it or skip calling this function, the first one will be default.
\section dialog_helper__result Create Dialog and Get Result \section dialog_helper__result Create Dialog and Get Result
Finally, we can call file dialog functions by we initialized YYCC::DialogHelper::FileDialog
\code
YYCC::yycc_u8string single_selection;
std::vector<YYCC::yycc_u8string> multiple_selection;
YYCC::DialogHelper::OpenFileDialog(params, single_selection);
YYCC::DialogHelper::OpenMultipleFileDialog(params, multiple_selection);
YYCC::DialogHelper::SaveFileDialog(params, single_selection);
YYCC::DialogHelper::OpenFolderDialog(params, single_selection);
\endcode
There are 4 file dialogs you can choose:
\li YYCC::DialogHelper::OpenFileDialog: Open single file
\li YYCC::DialogHelper::OpenMultipleFileDialog: Open multiple files
\li YYCC::DialogHelper::SaveFileDialog: Save single file
\li YYCC::DialogHelper::OpenFolderDialog: Open single directory
\subsection dialog_helper__result__arguments Arguments
Among these 4 functions, the first argument always is the reference to YYCC::DialogHelper::FileDialog.
Function will use it to decide what should be shown in this file dialog.
The second argument always is the reference to the container receiving the result.
For single selection, the return type is \c yycc_u8string.
For multiple selection, the return type is a list of strings: \c std::vector<yycc_u8string>.
\subsection dialog_helper__result__return_value Return Value
Please note among these 4 functions will return a bool as its return value to indicate the success of function.
If they return false, it means that the execution of functions are failed or user click Cancel button.
In this case, there is no guaranteen to the content of second argument (the real return value).
\section dialog_helper__notes Notes
You may notice there are various classes which we never introduce.
Because they are intermediate classes and should not be used by programmer.
For example:
\li YYCC::DialogHelper::WinFileDialog: The converted YYCC::DialogHelper::FileDialog passed to Windows.
\li YYCC::DialogHelper::WinFileFilters: Same as YYCC::DialogHelper::WinFileDialog. It will be passed to Windows functions.
\li etc...
*/ */

View File

@ -37,6 +37,8 @@ YYCC supports following convertions:
\li YYCC::EncodingHelper::CharToChar: Convert string between 2 different code pages. It's a shortcut of calling CharToWchar and WcharToChar successively. \li YYCC::EncodingHelper::CharToChar: Convert string between 2 different code pages. It's a shortcut of calling CharToWchar and WcharToChar successively.
\li YYCC::EncodingHelper::WcharToUTF8: Convert \c wchar_t string to UTF8 string. \li YYCC::EncodingHelper::WcharToUTF8: Convert \c wchar_t string to UTF8 string.
\li YYCC::EncodingHelper::UTF8ToWchar: The reversed convertion of WcharToUTF8. \li YYCC::EncodingHelper::UTF8ToWchar: The reversed convertion of WcharToUTF8.
\li YYCC::EncodingHelper::CharToUTF8: Convert code page specified string to UTF8 string.
\li YYCC::EncodingHelper::UTF8ToChar: The reversed convertion of CharToUTF8.
Code Page is a Windows concept. Code Page is a Windows concept.
If you don't understand it, please view corresponding Microsoft documentation. If you don't understand it, please view corresponding Microsoft documentation.

View File

@ -0,0 +1,87 @@
/**
\page exception_helper Unhandled Exception Handler
Most Linux users are familiar with core dump.
However core dump is a tough work on Windows especially most Windows users are naive for getting core dump.
So it is essential to make an easy-to-visit core dump Feature for Windows program.
YYCC provides this feature in YYCC::ExceptionHelper.
You may know Google also has a similar and universal project called Crashpad used by Google Chrome.
That's right. But it is too heavy.
I just want to implement a tiny but worked core dump feature on Windows.
This module is Windows specific.
It will be invisible on other platforms.
\section exception_helper__usage Usage
\subsection exception_helper__usage__code Register Code
In most scenarios, programmer only need call YYCC::ExceptionHelper::Register() when program started or module loaded.
And call YYCC::ExceptionHelper::Unregister when program exited or module unloaded.
All details are hidden by these 2 feature.
Programmer do not need worried about the implementation of unhandled exception handler.
\subsection exception_helper__usage__location Location
When unhandled exception occurs,
unhandled exception handler will try to record error log and core dump in following path:
\li Error Log: <TT>\%LOCALAPPDATA\%\\CrashDumps\\<I>program.exe</I>.<I>pid</I>.log</TT>
\li Core Dump: <TT>\%LOCALAPPDATA\%\\CrashDumps\\<I>program.exe</I>.<I>pid</I>.dmp</TT>
The italic characters <I>program.exe</I> and <I>pid</I> will be replaced by program name and process ID respectively at runtime.
Directory <TT>\%LOCALAPPDATA\%\\CrashDumps</TT> also is Windows used crash dump directory.
So you may see some other core dumps done by Windows in it.
\subsection exception_helper__usage__last_remedy Last Remedy
If unhandled exception handler occurs error, these stuff may not be generated correctly.
The end user may not find them and send them to you.
There is a last remedy for this scenario.
Unhandled exception handler will still output error log in \c stderr no matter whether error log or core dump is created.
So end user always can fetch error log from console.
You only need to instruct end user open command prompt, launch application, reproduce error and get the output error log in console.
In this case, you can not get core dump. But you can get error log.
It is not good for debugging but it is better than nothing.
Also please note the last remedy may still have a little bit possibility to occurs error and output nothing,
especially the error occurs in back trace function.
There is no guaranteen that unhandled exception handler must generate error log and core dump.
\section exception_helper__notes Notes
\subsection exception_helper__notes__thread_safe Thread Safe
All exposed functions in YYCC::ExceptionHelper are thread safe.
The implementation uses \c std:mutex to ensure this.
\subsection exception_helper__notes__singleton Singleton Handler
YYCC::ExceptionHelper also have a mechanism that make sure the same unhandled exception handler implementation only appear once in the same process.
For example, you have an executable program A.exe, and 2 dynamic libraries B.dll and C.dll.
A.exe and B.dll use YYCC unhandled exception handler feature but C.dll not.
A.exe will load B.dll and C.dll at runtime.
Although both A.exe and B.dll call YYCC::ExceptionHelper::Register(),
when unhandled exception occurs, there is only one error report output,
which may be generated by A.exe or B.dll accoridng to their order of loading.
The core purpose of this is making sure the program will not output too many error report for the same unhandled exception,
no matter how many modules calling YYCC::ExceptionHelper::Register() are loaded.
Only one error report is enough.
More precisely, we use \c CreateMutexW to create an unique mutex in Windows global scope,
to make sure YYCC::ExceptionHelper::Register() only run once in the same process.
It is very like the implementation of singleton application.
\subsection exception_helper__notes__recursive_calling Recursive Calling
The implementation of unhandled exception handler may also will throw exception.
This will cause infinite recursive calling.
YYCC::ExceptionHelper has internal mechanism to prevent this bad case.
If this really happened, the handler will quit silent and will not cause any issue.
Programmer don't need to worry about this.
*/

73
doc/src/fs_path_patch.dox Normal file
View File

@ -0,0 +1,73 @@
/**
\page fs_path_patch std::filesystem::path Patch
As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,
and in other platforms, it is simple \c char.
Due to this, if you try to create a \c std::filesystem::path instance by calling constructor with an UTF8 char sequence on Windows,
the library implementation will assume your input is based on current Windows code page, not UTF8.
And the final path stored in \c std::filesystem::path is not what you expcected.
This patch gives you a way to create \c std::filesystem::path
and extract path string stored in \c std::filesystem::path with UTF8 encoding.
This patch namespace always use UTF8 as its argument.
You should use the functions provided by this namespace on any platforms
instead of vanilla \c std::filesystem::path functions.
However, if your C++ standard is higher than C++ 20,
you can directly use UTF8 string pointer and string container in \c std::filesystem::path,
because standard library has supported them.
This patch only just want to provide an uniform programming experience.
This patch is served for Windows but also works on other plaftoms.
If you are in Windows, this patch will perform extra operations to achieve goals,
and in other platforms, they just redirect request to corresponding vanilla C++ functions.
\section fs_path_patch__from_utf8_path Create Path from UTF8 String
YYCC::FsPathPatch::FromUTF8Path provides this feature.
It accepts an string pointer to UTF8 string and try to create \c std::filesystem::path from it.
Function will throw exception if encoding convertion or constructor self failed.
There are some example:
\code
auto foobar_path = YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("/foo/bar"));
auto slashed_path = foobar_path / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("test"));
auto replaced_ext = foobar_path.replace_extension(YYCC::FsPathPatch::FromUTF8Path(YYCC_U8(".txt")));
\endcode
For first line in example, it is obvious that you can create a \c std::filesystem::path from this function.
However, for the second and third line in example, what we want to tell you is
that you should always use this function in other \c std::filesystem::path functions requiring path string.
\c std::filesystem::path is a very \e conservative class.
Most of its functions only accept \c std::filesystem::path self as argument.
For example, \c std::filesystem::path::replace_extension do not accept string as argument.
It accepts a reference to \c std::filesystem::path as argument.
(it still is possible that pass string pointer or string container to it because they can be converted to \c std::filesystem::path implicitly.)
It's great. This is what we expected!
We now can safely deliver the result generated by our function to these functions,
and don't need to worry about the encoding of we provided string.
Because all strings have been converted to \c std::filesystem::path by our function before passing them.
So, the second line will produce \c "/foo/bar/test"
and the third line will produce \c "/foo/bar.txt" in any platforms.
You may notice std::filesystem::u8path.
However it is depracted since C++ 20,
because \c std::filesystem::path directly supports UTF8 by \c char8_t since C++ 20.
Because C++ standard is volatile, we create this function to have an uniform programming experience.
\section fs_path_patch__to_utf8_path Extract UTF8 Path String from Path
YYCC::FsPathPatch::ToUTF8Path provides this feature.
It basically is the reversed operation of YYCC::FsPathPatch::FromUTF8Path.
It is usually used when you have done all path work in \c std::filesystem::path
and want to get the result.
There is an example:
\code
auto foobar_path = YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("/foo/bar"));
auto result = YYCC::FsPathPatch::ToUTF8Path(foobar_path / YYCC::FsPathPatch::FromUTF8Path(YYCC_U8("test")));
\endcode
*/

View File

@ -37,6 +37,14 @@
\li \subpage string_helper \li \subpage string_helper
\li \subpage parser_helper
\li \subpage console_helper
\li \subpage io_helper
\li \subpage fs_path_patch
<B>Advanced Features</B> <B>Advanced Features</B>
\li \subpage config_manager \li \subpage config_manager
@ -48,8 +56,14 @@
\li \subpage win_import \li \subpage win_import
\li \subpage com_helper
\li \subpage dialog_helper \li \subpage dialog_helper
\li \subpage win_fct_helper
\li \subpage exception_helper
</TD> </TD>
</TR> </TR>
</TABLE> </TABLE>

View File

@ -2,14 +2,23 @@
\page intro Introduction to YYCCommonplace \page intro Introduction to YYCCommonplace
YYCCommonplace, or YYC Commonplace (abbr. YYCC), is a static library providing various useful C++ functions when programming with standard library or Windows environment. YYCCommonplace, or YYC Commonplace (abbr. YYCC),
is a static library providing various useful C++ functions
when programming with standard library or Windows environment.
Actually YYCC provides the functions which I frequently used in my personal projects. During the development of a few projects,
Thus I do not need copy these functions from one project to another project. I gradually understand how Windows make the compromise with the code written by its old developers,
I can write them once and use them everywhere. and what is developer wanted in contemporary C++ standard library under Windows environment.
It's also good for bug fix. So I create this static library for all of my C++ project.
If I found bug in these code, I only need to fix it in this project. After this, I do not need to write these duplicated code in each project.
Otherwise I need to fix them one by one in each project because they share the same code. I can use a clear and easy way to manage these codes.
I can easily fix issues found in project using this library by updating a single project,
rather than fixing these duplicated code in each project one by one
because all of them share the same implementations.
This project mainly is served for my personal use.
But I would be honored if you would like to use this in your project.
Almost of my projects will gradually adapt to this project and drop their own individual implementations.
\section intro__why Why YYCCommonplace \section intro__why Why YYCCommonplace
@ -71,6 +80,4 @@ Before using this library, I suggest you read this manual fully to have a full o
Otherwise you may make mistake during using this library. Otherwise you may make mistake during using this library.
I suggest you read this manual from top to bottom in the left tree panel, one by one. I suggest you read this manual from top to bottom in the left tree panel, one by one.
This library is a static library.
*/ */

43
doc/src/io_helper.dox Normal file
View File

@ -0,0 +1,43 @@
/**
\page io_helper IO Helper
YYCC::IOHelper currently only has one function and one macro.
\section io_helper__ptr_pri_padding Pointer Print Padding
When printing pointer on screen, programmer usually left-pad zero to make it looks good.
However, the count of zero for padding is different in x86 and x64 architecture (8 for x86 and 16 for x64).
Macro \c PRI_XPTR_LEFT_PADDING will help you to resolve this issue.
Macro \c PRI_XPTR_LEFT_PADDING will be defined to following value according to the target system architecture.
\li \c "08": On x86 system.
\li \c "016": On x64 system.
There is an example for how to use it:
\code
void* raw_ptr = blabla();
std::printf(stdout, "Raw Pointer 0x%" PRI_XPTR_LEFT_PADDING PRIXPTR, raw_ptr);
\endcode
Note \c PRIXPTR is defined by standard library for formatting pointer as hexadecimal style.
\section io_helper__utf8_fopen UTF8 fopen
In Windows, standard \c std::fopen can not handle UTF8 file name in common environment.
So we create this function to give programmer an universal \c fopen in UTF8 style.
In Windows platform, this function will try to convert its argument to \c wchar_t
and calling Microsoft specific \c _wfopen function to open file.
If encoding convertion or \c _wfopen failed, this function will return \c nullptr like \c std::fopen does.
In other platforms, it will simply redirect calling to \c std::fopen.
There is a simple example:
\code
FILE* fs = YYCC::IOHelper::FOpen(YYCC_U8("/path/to/file"), YYCC_U8("rb"));
\endcode
*/

View File

@ -96,6 +96,24 @@ This macro will do this automatically.
In detail, this macro do a \c reinterpret_cast to change the type of given argument to \c const \c yycc_char8_t* forcely. In detail, this macro do a \c reinterpret_cast to change the type of given argument to \c const \c yycc_char8_t* forcely.
This ensure that declared UTF8 literal is compatible with YYCC UTF8 types. This ensure that declared UTF8 literal is compatible with YYCC UTF8 types.
\subsection library_encoding__utf8_literal__char Single Char
Same as UTF8 literal, YYCC allow you cast normal \c char into \c yycc_char8_t as following code:
\code
YYCC_U8_CHAR('A')
\endcode
YYCC_U8_CHAR is a macro.
It just simply use \c static_cast to cast given value to \c yycc_char8_t.
It doesn't mean that you can cast non-ASCII characters,
because the space these characters occupied usually more than the maximum value of \c char.
For example, following code is \b invalid:
\code
YYCC_U8_CHAR('文') // INVALID!
\endcode
\subsection library_encoding__utf8_literal__concatenation Literal Concatenation \subsection library_encoding__utf8_literal__concatenation Literal Concatenation
YYCC_U8 macro also works for string literal concatenation: YYCC_U8 macro also works for string literal concatenation:

80
doc/src/parser_helper.dox Normal file
View File

@ -0,0 +1,80 @@
/**
\page parser_helper Parser Helper
This helper is served for the convertion between number and string.
\section parser_helper_supported_types Supported Types
Functions located in this helper support the convertion between string and following types:
\li Integral types (except \c bool): \c int, \c uint32_t, \c char and etc.
\li Floating point types: \c float, \c double and etc.
\li \c bool
Please note in C++, \c bool is integral type but we list it individually because parser will treat it specially.
For \c bool type, parser will try doing convertion between it and \c "true" \c "false" string.
(\b case-sensitive. It means that \c true will only be converted to \c "true" and \c "TRUE" can not be recognised.)
\section parser_helper__try_parse Try Parse
YYCC::ParserHelper::TryParse will try to parse string into caller specified type.
All of them accept an UTF8 string view at first argument,
require that you provide a container receiving converted result in the second argument,
and return a bool value to indicate whether the convertion is successful.
There are some examples:
\code
uint32_t val;
YYCC::ParserHelper::TryParse<uint32_t>(YYCC_U8("123"), val);
YYCC::ParserHelper::TryParse<uint32_t>(YYCC_U8("7fff"), val, 16);
\endcode
For integral type, this function allows caller to specify extra argument providing the base of given number string.
\section parser_helper__parse Parse
YYCC::ParserHelper::Parse is similar to YYCC::ParserHelper::TryParse.
But it will not return bool value to indicate success and doesn't have the argument receiving result.
It only accepts an UTF8 string view as the only one argument, and return result directly.
If the convertion failed, the return value is \b undefined (but usually is the default value of given type).
There is an example:
\code
uint32_t val = YYCC::ParserHelper::Parse<uint32_t>(YYCC_U8("123"));
\endcode
Please note, for integral types, there is no base argument in YYCC::ParserHelper::Parse.
Please use YYCC::ParserHelper::TryParse instead.
Using this function is dangerous if the validation of your input is important.
In this case, please use YYCC::ParserHelper::TryParse instead.
\section parser_helper__to_string To String
YYCC::ParserHelper::ToString basically is the reversed operation of YYCC::ParserHelper::Parse.
It gets the string representation of given type.
The only argument of these functions is the type which need to be converted to its string representation.
And they will return yycc_u8string as result.
There is an example:
\code
auto result = YYCC::ParserHelper::ToString<uint32_t>(UINT32_C(114));
\endcode
\section parser_helper__notes Notes
All functions within this helper are implementated by standard library functions.
These functions just make a good wrapper for complex standard library functions.
And give you a experience like C\# parser functions.
Basically, all functions located in this helper have possibility to throw exception.
But this possibility are more close to the possibility that \c new statement throw \c std::bad_alloc.
So in most cases you can assume these functions will not throw any exception.
All functions are template functions.
The argument of template is the type these functions need to be processed.
Although C++ have \e smart template type deduction,
it would be better to specify template argument manually to explicitly specify your desired type.
*/

View File

@ -2,8 +2,104 @@
\page string_helper String Helper \page string_helper String Helper
\section string_helper__printf Printf VPrintf
\section string_helper_lower_upper Lower Upper YYCC::StringHelper provides 4 functions for formatting string.
These functions are mainly provided to programmer who can not use C++ 20 \c std::format feature.
\code
bool Printf(yycc_u8string&, const yycc_char8_t*, ...);
bool VPrintf(yycc_u8string&, const yycc_char8_t*, va_list argptr);
yycc_u8string Printf(const yycc_char8_t*, ...);
yycc_u8string VPrintf(const yycc_char8_t*, va_list argptr);
\endcode
YYCC::StringHelper::Printf and YYCC::StringHelper::VPrintf is similar to \c std::sprintf and \c std::vsprintf.
YYCC::StringHelper::Printf accepts UTF8 format string and variadic arguments specifying data to print.
This is commonly used by programmer.
However, YYCC::StringHelper::VPrintf also do the same work but its second argument is \c va_list,
the representation of variadic arguments.
It is mostly used by other function which has variadic arguments.
The only difference between these function and standard library functions is
that you don't need to worry about whether the space of given buffer is enough,
because these functions help you to calculate this internally.
There is the same design like we introduced in \ref encoding_helper.
There are 2 overloads for YYCC::StringHelper::Printf and YYCC::StringHelper::VPrintf respectively.
First overload return bool value and require a string container as argument for storing result.
The second overload return result string directly.
As you expected, first overload will return false if fail to format string (this is barely happened).
and second overload will return empty string when formatter failed.
\section string_helper__replace Replace
YYCC::StringHelper provide 2 functions for programmer do string replacement:
\code
void Replace(yycc_u8string&, const yycc_char8_t*, const yycc_char8_t*);
yycc_u8string Replace(const yycc_char8_t*, const yycc_char8_t*, const yycc_char8_t*);
\endcode
The first overload will do replacement in given string container directly.
The second overload will produce a copy of original string and do replacement on the copied string.
YYCC::StringHelper::Replace has special treatments for following scenarios:
\li If given string is empty or nullptr, the return value will be empty.
\li If the character sequence to be replaced is nullptr or empty string, no replacement will happen.
\li If the character sequence will be replaced into string is nullptr or empty, it will simply delete found character sequence from given string.
\section string_helper__join Join
YYCC::StringHelper provide an universal way for joining string and various specialized join functions.
\subsection string_helper__join__universal Universal Join Function
Because C++ list types are various.
There is no unique and convenient way to create an universal join function.
So we create YYCC::StringHelper::JoinDataProvider to describe join context.
Before using universal join function,
you should setup YYCC::StringHelper::JoinDataProvider first, the context of join function.
It actually is an \c std::function object which can be easily fetched by C++ lambda syntax.
This function pointer accept a reference to \c yycc_u8string_view,
programmer should set it to the string to be joined when at each calling.
And this function pointer return a bool value to indicate the end of join.
You can simply return \c false to terminate join process.
The argument you assigned to argument will not be taken into join process when you return false.
Then, you can pass the created YYCC::StringHelper::JoinDataProvider object to YYCC::StringHelper::Join function.
And specify decilmer at the same time.
Then you can get the final joined string.
There is an example:
\code
std::vector<yycc_u8string> data {
YYCC_U8(""), YYCC_U8("1"), YYCC_U8("2"), YYCC_U8("")
};
auto iter = data.cbegin();
auto stop = data.cend();
auto joined_string = YYCC::StringHelper::Join(
[&iter, &stop](yycc_u8string_view& view) -> bool {
if (iter == stop) return false;
view = *iter;
++iter;
return true;
},
decilmer
);
\endcode
\subsection string_helper__join__specialized Specialized Join Function
Despite universal join function,
YYCC::StringHelper also provide some specialized join functions for commonly used types.
Current we support following join function:
\li \c std::vector<yycc_u8string>: With an extra option which allow join it with reversed order.
\section string_helper__lower_upper Lower Upper
String helper provides Python-like string lower and upper function. String helper provides Python-like string lower and upper function.
Both lower and upper function have 2 overloads: Both lower and upper function have 2 overloads:
@ -18,7 +114,7 @@ Second overload accepts a mutable string container as argument and will make all
You can choose on of them for your flavor and requirements. You can choose on of them for your flavor and requirements.
Upper also has similar 2 overloads. Upper also has similar 2 overloads.
\section string_helper_split Split \section string_helper__split Split
String helper provides Python-like string split function. String helper provides Python-like string split function.
It has 2 types for you: It has 2 types for you:
@ -28,16 +124,16 @@ std::vector<yycc_u8string> Split(const yycc_u8string_view&, const yycc_char8_t*)
std::vector<yycc_u8string_view> SplitView(const yycc_u8string_view&, const yycc_char8_t*); std::vector<yycc_u8string_view> SplitView(const yycc_u8string_view&, const yycc_char8_t*);
\endcode \endcode
All these overloads take a string view as the first argument for the string need to be split. All these overloads take a string view as the first argument representing the string need to be split.
The second argument is a raw string pointer representing the decilmer for splitting. The second argument is a raw string pointer representing the decilmer for splitting.
The only difference between these 2 split function are overt according to their names. The only difference between these 2 split function are overt according to their names.
The first split function will return a list of copied string as its split result. The first split function will return a list of copied string as its split result.
The second split function will return a list of string view as its split result, The second split function will return a list of string view as its split result,
and it will keep valid as long as the life time of your given string view argument. and it will keep valid as long as the life time of your given string view argument.
It also means that the last type will cost less memory if you don't need the copy of original string. It also means that the last overload will cost less memory if you don't need the copy of original string.
If the source string (the string need to be split) is empty, or the decilmer is \c nullptr or empty, If the source string (the string need to be split) is empty, or the decilmer is \c nullptr or empty,
the result will only has 1 item and this item is source string itself. the result will only has 1 item and this item is source string itself.
There is no way that this method return an empty list, except the code is buggy. There is no way that these methods return an empty list, except the code is buggy.
*/ */

View File

@ -0,0 +1,17 @@
/**
\page win_fct_helper Windows Function Helper
This helper give a more convenient way to call Windows functions.
This namespace is Windows specific.
It will be entirely invisible in other platforms.
Currently this namespace has following functions:
\li YYCC::WinFctHelper::GetCurrentModule: Get the handle to current module.
\li YYCC::WinFctHelper::GetTempDirectory: Get temporary directory in Windows.
\li YYCC::WinFctHelper::GetModuleFileName: Get the path to module in file system by given handle.
\li YYCC::WinFctHelper::GetLocalAppData: Get the path inside \%LOCALAPPDATA\%
*/

View File

@ -28,7 +28,7 @@ This guard can solve following issues:
<LI> <LI>
Programmer can not use \c std::max and \c std::min normally. Programmer can not use \c std::max and \c std::min normally.
<UL> <UL>
<LI>Windows defines \c MAX and \c MIN as macros for personal use. This is why this happend.</LI> <LI>Windows defines \c MAX and \c MIN as macros for personal use. This is why this happened.</LI>
<LI>Guard defines some special macros to tell Windows do not create these 2 macros.</LI> <LI>Guard defines some special macros to tell Windows do not create these 2 macros.</LI>
</UL> </UL>
</LI> </LI>

View File

@ -7,37 +7,48 @@ IF EXIST %README_PATH% (
EXIT /b EXIT /b
) )
:: Create essential folder :: Create main binary directory
MKDIR bin MKDIR bin
CD bin CD bin
:: Create build folder
MKDIR Win32 MKDIR Win32
MKDIR x64 MKDIR x64
MKDIR documentation MKDIR documentation
:: Create install folder
MKDIR install MKDIR install
CD install
MKDIR Win32_Debug
MKDIR Win32_Release
MKDIR x64_Debug
MKDIR x64_Release
CD ..
:: Build for Win32 :: Build for Win32
CD Win32 CD Win32
cmake -G "Visual Studio 16 2019" -A Win32 -DYYCC_BUILD_TESTBENCH=ON ../.. cmake -G "Visual Studio 16 2019" -A Win32 -DYYCC_BUILD_TESTBENCH=ON ../..
cmake --build . --config Debug cmake --build . --config Debug
cmake --install . --prefix=../install --config Debug cmake --install . --prefix=../install/Win32_Debug --config Debug
cmake --build . --config Release cmake --build . --config Release
cmake --install . --prefix=../install --config Release cmake --install . --prefix=../install/Win32_Release --config Release
CD .. CD ..
:: Build for x64 :: Build for x64
CD x64 CD x64
cmake -G "Visual Studio 16 2019" -A x64 -DYYCC_BUILD_TESTBENCH=ON ../.. cmake -G "Visual Studio 16 2019" -A x64 -DYYCC_BUILD_TESTBENCH=ON ../..
cmake --build . --config Debug cmake --build . --config Debug
cmake --install . --prefix=../install --config Debug cmake --install . --prefix=../install/x64_Debug --config Debug
cmake --build . --config Release cmake --build . --config Release
cmake --install . --prefix=../install --config Release cmake --install . --prefix=../install/x64_Release --config Release
CD .. CD ..
:: Build for documentation :: Build for documentation
CD documentation CD documentation
cmake -DYYCC_BUILD_DOC=ON ../.. cmake -G "Visual Studio 16 2019" -A x64 -DYYCC_BUILD_DOC=ON ../..
cmake --build . --config Release cmake --build . --config Release
:: cmake --install . --prefix=../install --config Release cmake --build . --target YYCCDocumentation
cmake --install . --prefix=../install/x64_Release --config Release
CD .. CD ..
ECHO DONE :: Exit to original path
CD ..
ECHO Windows CMake Build Done

50
script/win_msvc_build.bat Normal file
View File

@ -0,0 +1,50 @@
@ECHO OFF
SET README_PATH=%CD%\README.md
IF EXIST %README_PATH% (
REM DO NOTHING
) ELSE (
ECHO Error: You must run this script at the root folder of this project!
EXIT /b
)
:: Enter main binary directory
CD bin
:: Create MSVC binary directory
MKDIR msvc_install
CD msvc_install
:: Create direcotries tree
MKDIR bin
MKDIR include
MKDIR lib
MKDIR share
CD bin
MKDIR Win32
MKDIR x64
CD ..
CD lib
MKDIR Win32\Debug
MKDIR Win32\Release
MKDIR x64\Debug
MKDIR x64\Release
CD ..
:: Exit MSVC binary directory
CD ..
:: Copy result
:: Copy include from x64_Release build
XCOPY install\x64_Release\include msvc_install\include\ /E /Y
:: Copy document from x64_Release build
XCOPY install\x64_Release\share msvc_install\share\ /E /Y
:: Copy binary testbench
COPY install\Win32_Release\bin\YYCCTestbench.exe msvc_install\bin\Win32\YYCCTestbench.exe /Y
COPY install\x64_Release\bin\YYCCTestbench.exe msvc_install\bin\x64\YYCCTestbench.exe /Y
:: Copy static library
COPY install\Win32_Debug\lib\YYCCommonplace.lib msvc_install\lib\Win32\Debug\YYCCommonplace.lib /Y
COPY install\Win32_Release\lib\YYCCommonplace.lib msvc_install\lib\Win32\Release\YYCCommonplace.lib /Y
COPY install\x64_Debug\lib\YYCCommonplace.lib msvc_install\lib\x64\Debug\YYCCommonplace.lib /Y
COPY install\x64_Release\lib\YYCCommonplace.lib msvc_install\lib\x64\Release\YYCCommonplace.lib /Y
:: Exit to original path
CD ..
ECHO Windows MSVC Build Done

View File

@ -14,6 +14,8 @@ PRIVATE
IOHelper.cpp IOHelper.cpp
StringHelper.cpp StringHelper.cpp
WinFctHelper.cpp WinFctHelper.cpp
# Natvis (only for MSVC)
$<$<CXX_COMPILER_ID:MSVC>:YYCC.natvis>
) )
target_sources(YYCCommonplace target_sources(YYCCommonplace
PUBLIC PUBLIC
@ -72,8 +74,8 @@ PRIVATE
# Install binary and headers # Install binary and headers
install(TARGETS YYCCommonplace install(TARGETS YYCCommonplace
EXPORT YYCCommonplaceTargets EXPORT YYCCommonplaceTargets
LIBRARY DESTINATION ${YYCC_INSTALL_PATH_LIB} LIBRARY DESTINATION ${YYCC_INSTALL_LIB_PATH}
ARCHIVE DESTINATION ${YYCC_INSTALL_PATH_LIB} ARCHIVE DESTINATION ${YYCC_INSTALL_LIB_PATH}
INCLUDES DESTINATION include INCLUDES DESTINATION ${YYCC_INSTALL_INCLUDE_PATH}
FILE_SET HEADERS DESTINATION include FILE_SET HEADERS DESTINATION ${YYCC_INSTALL_INCLUDE_PATH}
) )

View File

@ -9,25 +9,6 @@
#include <shlobj_core.h> #include <shlobj_core.h>
#include "WinImportSuffix.hpp" #include "WinImportSuffix.hpp"
/**
* @brief COM fucntions related namespace.
* @details
* This namespace is Windows specific and is unavailable on other platforms.
*
* This namespace contain a COM Guard which make sure COM was initialized in current module when loading current module.
* It is essential because all calling to COM functions should be under the premise that COM has been initialized.
* This guard also will uninitialize COM when unloading this module.
*
* This namespace also provided various memory-safe types for interacting with COM functions.
* Although Microsoft also has similar smart pointer called \c CComPtr.
* But this library is eager to hide all Microsoft-related functions calling.
* Using \c CComPtr is not corresponding with the philosophy of this library.
* So these std-based smart pointer type were created.
*
* This namespace is used by internal functions as intended.
* They should not be used outside of this library.
* But if you compel to use them, it is also okey.
*/
namespace YYCC::COMHelper { namespace YYCC::COMHelper {
/** /**

View File

@ -101,7 +101,7 @@ namespace YYCC::ConfigManager {
virtual ~NumberSetting() {} virtual ~NumberSetting() {}
_Ty Get() const { return m_Data; } _Ty Get() const { return m_Data; }
bool Set(_Ty new_data) { bool Set(_Ty new_data) {
// validate data // validate data
if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(new_data)) if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(new_data))
return false; return false;
@ -137,21 +137,17 @@ namespace YYCC::ConfigManager {
class StringSetting : public AbstractSetting { class StringSetting : public AbstractSetting {
public: public:
StringSetting(const yycc_char8_t* name, const yycc_char8_t* default_value, Constraint<yycc_u8string> constraint = Constraint<yycc_u8string> {}) : StringSetting(const yycc_char8_t* name, const yycc_u8string_view& default_value, Constraint<yycc_u8string_view> constraint = Constraint<yycc_u8string_view> {}) :
AbstractSetting(name), m_Data(), m_DefaultData(), m_Constraint(constraint) { AbstractSetting(name), m_Data(), m_DefaultData(), m_Constraint(constraint) {
if (default_value != nullptr) { m_Data = default_value;
m_Data = default_value; m_DefaultData = default_value;
m_DefaultData = default_value;
}
} }
virtual ~StringSetting() {} virtual ~StringSetting() {}
const yycc_u8string& Get() const { return m_Data; } const yycc_u8string& Get() const { return m_Data; }
bool Set(const yycc_char8_t* new_data) { bool Set(const yycc_u8string_view& new_data) {
// check data validation // check data validation
if (new_data == nullptr) if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(new_data))
return false;
if (m_Constraint.IsValid() && !m_Constraint.m_CheckFct(m_Data))
return false; return false;
// assign data // assign data
m_Data = new_data; m_Data = new_data;
@ -194,7 +190,7 @@ namespace YYCC::ConfigManager {
} }
yycc_u8string m_Data, m_DefaultData; yycc_u8string m_Data, m_DefaultData;
Constraint<yycc_u8string> m_Constraint; Constraint<yycc_u8string_view> m_Constraint;
}; };
#pragma endregion #pragma endregion

View File

@ -7,60 +7,7 @@
/** /**
* @brief The namespace providing universal Console visiting functions like C-Sharp Console class. * @brief The namespace providing universal Console visiting functions like C-Sharp Console class.
* @details * @details
* \par Why this Namespace * \ref console_helper
* Windows console doesn't support UTF8 very well.
* The standard input output functions can not work properly on Windows with UTF8.
* So we create this namespace and provide various console-related functions
* to patch Windows console and let it more like the console in other platforms.
* \par
* The function provided in this function can be called in any platforms.
* In Windows, the implementation will use Windows native function,
* and in other platform, the implementation will redirect request to standard C function
* like std::fputs and etc.
* So the programmer do not need to be worried about which function should they use,
* and don't need to use macro to use different IO function in different platforms.
* It is just enough that fully use the functions provided in this namespace.
* \par
* All IO functions this namespace provided are UTF8-based.
* It also means that input output string should always be UTF8 encoded.
*
* \par Input Functions
* Please note that EOL will automatically converted into LF on Windows platform, not CRLF.
* This action actually is removing all CR chars in result string.
* This behavior affect nothing in most cases but it still is possible break something in some special case.
* \par
* Due to implementation, if you decide to use this function,
* you should give up using any other function to read stdin stream,
* such as std::gets() and std::cin.
* Because this function may read chars which is more than needed.
* These extra chars will be stored in this function and can be used next calling.
* But these chars can not be visited by stdin again.
* This behavior may cause bug.
* So if you decide using this function, stick on it and do not change.
* \par
* Due to implementation, this function do not support hot switch of stdin.
* It means that stdin can be redirected before first calling of this function,
* but it should not be redirected during program running.
* The reason is the same one introduced above.
*
* \par Output Functions
* In current implementation, EOL will not be converted automatically to CRLF.
* This is different with other stream read functions provided in this namespace.
* \par
* Comparing with other stream read functions provided in this namespace,
* stream write function support hot switch of stdout and stderr.
* Because they do not have internal buffer storing something.
* \par
* In this namespace, there are various stream write function.
* There is a list telling you how to choose one from them for using:
* \li Functions with leading "Err" will write data into stderr,
* otherwise they will write data into stdout.
* \li Functions with embedded "Format" are output functions with format feature
* like std::fprintf(), otherwise the functions with embedded "Write" will
* only write plain string like std::fputs().
* \li Functions with trailing "Line" will write extra EOL to break current line.
* This is commonly used, otherwise functions will only write the text provided by arguments,
* without adding something.
*/ */
namespace YYCC::ConsoleHelper { namespace YYCC::ConsoleHelper {

View File

@ -191,6 +191,44 @@ return ret;
#pragma endregion #pragma endregion
#pragma region CharToUTF8
bool CharToUTF8(const std::string_view& src, yycc_u8string& dst, UINT code_page) {
std::string adapted_dst;
bool ret = CharToChar(src, adapted_dst, code_page, CP_UTF8);
if (ret) dst = ToUTF8(adapted_dst);
return ret;
}
bool CharToUTF8(const char* src, yycc_u8string& dst, UINT code_page) {
CONVFCT_TYPE2(CharToUTF8, char, yycc_char8_t, code_page);
}
yycc_u8string CharToUTF8(const std::string_view& src, UINT code_page) {
CONVFCT_TYPE3(CharToUTF8, char, yycc_char8_t, code_page);
}
yycc_u8string CharToUTF8(const char* src, UINT code_page) {
CONVFCT_TYPE4(CharToUTF8, char, yycc_char8_t, code_page);
}
#pragma endregion
#pragma region UTF8ToChar
bool UTF8ToChar(const yycc_u8string_view& src, std::string& dst, UINT code_page) {
std::string_view adapted_src(ToOrdinaryView(src));
return CharToChar(adapted_src, dst, CP_UTF8, code_page);
}
bool UTF8ToChar(const yycc_char8_t* src, std::string& dst, UINT code_page) {
CONVFCT_TYPE2(UTF8ToChar, yycc_char8_t, char, code_page);
}
std::string UTF8ToChar(const yycc_u8string_view& src, UINT code_page) {
CONVFCT_TYPE3(UTF8ToChar, yycc_char8_t, char, code_page);
}
std::string UTF8ToChar(const yycc_char8_t* src, UINT code_page) {
CONVFCT_TYPE4(UTF8ToChar, yycc_char8_t, char, code_page);
}
#pragma endregion
#endif #endif

View File

@ -19,6 +19,7 @@ namespace YYCC::EncodingHelper {
#define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8. #define _YYCC_U8(strl) u8 ## strl ///< The assistant macro for YYCC_U8.
#define YYCC_U8(strl) (reinterpret_cast<const ::YYCC::yycc_char8_t*>(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding. #define YYCC_U8(strl) (reinterpret_cast<const ::YYCC::yycc_char8_t*>(_YYCC_U8(strl))) ///< The macro for creating UTF8 string literal. See \ref library_encoding.
#define YYCC_U8_CHAR(chr) (static_cast<YYCC::yycc_char8_t>(chr)) ///< The macro for casting normal char into YYCC UTF8 char type.
const yycc_char8_t* ToUTF8(const char* src); const yycc_char8_t* ToUTF8(const char* src);
yycc_char8_t* ToUTF8(char* src); yycc_char8_t* ToUTF8(char* src);
@ -57,6 +58,16 @@ namespace YYCC::EncodingHelper {
bool UTF8ToWchar(const yycc_char8_t* src, std::wstring& dst); bool UTF8ToWchar(const yycc_char8_t* src, std::wstring& dst);
std::wstring UTF8ToWchar(const yycc_u8string_view& src); std::wstring UTF8ToWchar(const yycc_u8string_view& src);
std::wstring UTF8ToWchar(const yycc_char8_t* src); std::wstring UTF8ToWchar(const yycc_char8_t* src);
bool CharToUTF8(const std::string_view& src, yycc_u8string& dst, UINT code_page);
bool CharToUTF8(const char* src, yycc_u8string& dst, UINT code_page);
yycc_u8string CharToUTF8(const std::string_view& src, UINT code_page);
yycc_u8string CharToUTF8(const char* src, UINT code_page);
bool UTF8ToChar(const yycc_u8string_view& src, std::string& dst, UINT code_page);
bool UTF8ToChar(const yycc_char8_t* src, std::string& dst, UINT code_page);
std::string UTF8ToChar(const yycc_u8string_view& src, UINT code_page);
std::string UTF8ToChar(const yycc_char8_t* src, UINT code_page);
#endif #endif

View File

@ -3,23 +3,6 @@
#include <filesystem> #include <filesystem>
/**
* @brief The patch namespace resolving \c std::filesystem::path encoding issue.
* @details
* This patch is Windows oriented.
* If you are in Windows, this patch will perform extra operations to achieve goals,
* and in other platforms, they just redirect request to corresponding vanilla C++ functions.
*
* As you know, the underlying char type of \c std::filesystem::path is \c wchar_t on Windows,
* and in other platforms, it is simple \c char.
* Due to this, if you passing UTF8 char sequence to \c std::filesystem::path on Windows,
* the library implementation will assume your input is based on current Windows code page, not UTF8.
* And the final path stored in \c std::filesystem::path is not what you expcected.
*
* This patch namespace always use UTF8 as its argument. There is no ambiguous issue.
* You should use the functions provided by this namespace on any platforms
* instead of vanilla \c std::filesystem::path functions.
*/
namespace YYCC::FsPathPatch { namespace YYCC::FsPathPatch {
/** /**

View File

@ -28,7 +28,7 @@ namespace YYCC::IOHelper {
return _wfopen(wpath.c_str(), wmode.c_str()); return _wfopen(wpath.c_str(), wmode.c_str());
#else #else
return std::fopen(u8_filepath, u8_mode); return std::fopen(EncodingHelper::ToOrdinary(u8_filepath), EncodingHelper::ToOrdinary(u8_mode));
#endif #endif
} }

View File

@ -84,7 +84,7 @@ namespace YYCC::ParserHelper {
return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data()); return yycc_u8string(buffer.data(), EncodingHelper::ToUTF8(ptr) - buffer.data());
} else if (ec == std::errc::value_too_large) { } else if (ec == std::errc::value_too_large) {
// too short buffer // too short buffer
// this should not happend // this should not happened
throw std::out_of_range("ToString() buffer is not sufficient."); throw std::out_of_range("ToString() buffer is not sufficient.");
} else { } else {
// unreachable // unreachable

73
src/YYCC.natvis Normal file
View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Microsoft Corporation, yyc12345.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-->
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<!-- Following XML are copied from Visual Studio embedded Natvis files. -->
<!-- <Microsoft Visual Studio Install Directory>\Common7\Packages\Debugger\Visualizers\stl.natvis -->
<!-- VC 2013 -->
<Type Name="std::basic_string&lt;YYCC::yycc_char8_t,*&gt;" Priority="MediumLow">
<AlternativeType Name="std::basic_string&lt;char8_t,*&gt;" />
<AlternativeType Name="std::basic_string&lt;unsigned char,*&gt;" />
<DisplayString Condition="_Myres &lt; _BUF_SIZE">{_Bx._Buf,s8}</DisplayString>
<DisplayString Condition="_Myres &gt;= _BUF_SIZE">{_Bx._Ptr,s8}</DisplayString>
<StringView Condition="_Myres &lt; _BUF_SIZE">_Bx._Buf,s8</StringView>
<StringView Condition="_Myres &gt;= _BUF_SIZE">_Bx._Ptr,s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">_Mysize</Item>
<Item Name="[capacity]" ExcludeView="simple">_Myres</Item>
<ArrayItems>
<Size>_Mysize</Size>
<ValuePointer Condition="_Myres &lt; _BUF_SIZE">_Bx._Buf</ValuePointer>
<ValuePointer Condition="_Myres &gt;= _BUF_SIZE">_Bx._Ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<!-- VC 2015+ ABI basic_string -->
<Type Name="std::basic_string&lt;YYCC::yycc_char8_t,*&gt;">
<AlternativeType Name="std::basic_string&lt;char8_t,*&gt;" />
<AlternativeType Name="std::basic_string&lt;unsigned char,*&gt;" />
<Intrinsic Name="size" Expression="_Mypair._Myval2._Mysize" />
<Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myres" />
<!-- _BUF_SIZE = 16 / sizeof(char) &lt; 1 ? 1 : 16 / sizeof(char) == 16 -->
<Intrinsic Name="bufSize" Expression="16" />
<Intrinsic Name="isShortString" Expression="capacity() &lt; bufSize()" />
<Intrinsic Name="isLongString" Expression="capacity() &gt;= bufSize()" />
<DisplayString Condition="isShortString()">{_Mypair._Myval2._Bx._Buf,s8}</DisplayString>
<DisplayString Condition="isLongString()">{_Mypair._Myval2._Bx._Ptr,s8}</DisplayString>
<StringView Condition="isShortString()">_Mypair._Myval2._Bx._Buf,s8</StringView>
<StringView Condition="isLongString()">_Mypair._Myval2._Bx._Ptr,s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<Item Name="[capacity]" ExcludeView="simple">capacity()</Item>
<Item Name="[allocator]" ExcludeView="simple">_Mypair</Item>
<ArrayItems>
<Size>_Mypair._Myval2._Mysize</Size>
<ValuePointer Condition="isShortString()">_Mypair._Myval2._Bx._Buf</ValuePointer>
<ValuePointer Condition="isLongString()">_Mypair._Myval2._Bx._Ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="std::basic_string_view&lt;YYCC::yycc_char8_t,*&gt;">
<AlternativeType Name="std::basic_string_view&lt;char8_t,*&gt;" />
<AlternativeType Name="std::basic_string_view&lt;unsigned char,*&gt;" />
<Intrinsic Name="size" Expression="_Mysize" />
<Intrinsic Name="data" Expression="_Mydata" />
<DisplayString>{_Mydata,[_Mysize],s8}</DisplayString>
<StringView>_Mydata,[_Mysize],s8</StringView>
<Expand>
<Item Name="[size]" ExcludeView="simple">size()</Item>
<ArrayItems>
<Size>size()</Size>
<ValuePointer>data()</ValuePointer>
</ArrayItems>
</Expand>
</Type>
</AutoVisualizer>

View File

@ -35,7 +35,6 @@ PRIVATE
# Install testbench only on Release mode # Install testbench only on Release mode
install(TARGETS YYCCTestbench install(TARGETS YYCCTestbench
EXPORT YYCCTestbenchTargets
CONFIGURATIONS Release CONFIGURATIONS Release
RUNTIME DESTINATION ${YYCC_INSTALL_PATH_BIN} RUNTIME DESTINATION ${YYCC_INSTALL_BIN_PATH}
) )