refactor: refactor doc layout
This commit is contained in:
200
doc/src/carton/arg_parser.dox
Normal file
200
doc/src/carton/arg_parser.dox
Normal file
@@ -0,0 +1,200 @@
|
||||
namespace YYCC::ArgParser {
|
||||
/**
|
||||
|
||||
\page arg_parser Universal Argument Parser
|
||||
|
||||
YYCC::ArgParser provides an universal way to parsing command line arguments.
|
||||
|
||||
Universal argument parser has similar design with universal config manager,
|
||||
it is highly recommand that read \ref config_manager chapter first,
|
||||
because you will have a clear understanding of this namespace after reading universal config manager chapter.
|
||||
|
||||
There is an example about how to use universal argument parser.
|
||||
In following content, we will describe it in detail.
|
||||
|
||||
\code{.cpp}
|
||||
class TestArgParser {
|
||||
public:
|
||||
TestArgParser() :
|
||||
m_IntArgument(YYCC_U8("int"), YYCC_U8_CHAR('i'), YYCC_U8("integral argument"), YYCC_U8("114514")),
|
||||
m_FloatArgument(nullptr, YYCC_U8_CHAR('f'), nullptr, nullptr, true),
|
||||
m_StringArgument(YYCC_U8("string"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true),
|
||||
m_BoolArgument(nullptr, YYCC_U8_CHAR('b'), nullptr),
|
||||
m_ClampedFloatArgument(YYCC_U8("clamped-float"), YYCC::ArgParser::AbstractArgument::NO_SHORT_NAME, nullptr, nullptr, true, YYCC::Constraints::GetMinMaxRangeConstraint<float>(-1.0f, 1.0f)),
|
||||
m_OptionContext(YYCC_U8("TestArgParser"), YYCC_U8("This is the test of argument parser."), {
|
||||
&m_IntArgument, &m_FloatArgument, &m_StringArgument,
|
||||
&m_BoolArgument, &m_ClampedFloatArgument
|
||||
}) {}
|
||||
~TestArgParser() {}
|
||||
|
||||
YYCC::ArgParser::NumberArgument<int32_t> m_IntArgument;
|
||||
YYCC::ArgParser::NumberArgument<float> m_FloatArgument;
|
||||
YYCC::ArgParser::StringArgument m_StringArgument;
|
||||
|
||||
YYCC::ArgParser::SwitchArgument m_BoolArgument;
|
||||
YYCC::ArgParser::NumberArgument<float> m_ClampedFloatArgument;
|
||||
|
||||
YYCC::ArgParser::OptionContext m_OptionContext;
|
||||
};
|
||||
|
||||
// Initialize argument parser.
|
||||
TestArgParser test;
|
||||
// Get argument list for parsing from standard C main function.
|
||||
auto al = YYCC::ArgParser::ArgumentList::CreateFromStd(argc, argv);
|
||||
// Start parsing
|
||||
test.Parse(al);
|
||||
// Get captured string argument
|
||||
if (test.m_StringArgument.IsCaptured())
|
||||
auto val = test.m_StringArgument.Get();
|
||||
\endcode
|
||||
|
||||
These code can resolve following command line:
|
||||
|
||||
\code{.sh}
|
||||
exec -i 114514 -f 2.0 --string fuck -b --clamped-float 0.5
|
||||
\endcode
|
||||
|
||||
For convenience, we define following terms used in this article.
|
||||
|
||||
\li Every items in command line: Argument.
|
||||
\li \c -i, \c --clamped-float: \b Switch / \b Option. the argument starts with dash or double dash.
|
||||
\li \c 114514: \b Value. the value of switch.
|
||||
|
||||
\section arg_parser__argument Argument
|
||||
|
||||
Argument is the leaf of argument parser.
|
||||
It has the same position as setting in universal config manager.
|
||||
|
||||
\subsection arg_parser__argument__presets Argument Presets
|
||||
|
||||
Like setting in universal config manager,
|
||||
we also provide various common used argument presets.
|
||||
Current'y we support following argument presets:
|
||||
|
||||
\li NumberArgument: The argument storing arithmetic type (except \c bool) inside. Such as <TT>-i 114514</TT> in example.
|
||||
\li StringArgument: The argument storing string inside. Such as <TT>--string fuck</TT> in example.
|
||||
\li SwitchArgument: The argument storing nothing. It is just a simple switch. Such as <TT>-b</TT> in example.
|
||||
|
||||
When constructing these argument,
|
||||
you need provide one from long name or short name, or both of them.
|
||||
Short name is the argument starting with dash and long name starts with double dash.
|
||||
You don't need add dash or double dash prefix when providing these names.
|
||||
Please note only ASCII characters, which can be displayed on screen, can be used in these names.
|
||||
|
||||
Optionally, you can provide description when constructing,
|
||||
which will tell user how this switch does and more infomation about this switch.
|
||||
And, you can add an example to tell user which value is valid.
|
||||
|
||||
Next, you can specify an argument to be optional.
|
||||
Optional argument can be absent in command line.
|
||||
Oppositely, non-optional argument must be presented in command line,
|
||||
otherwise parser will return false to indicate an error.
|
||||
For checking whether an optional argument is specified,
|
||||
please call AbstractArgument::IsCaptured().
|
||||
|
||||
Last, you can optionally assign a constraint to it,
|
||||
to help argument limit its value.
|
||||
|
||||
However SwitchArgument must be optional argument.
|
||||
Because it is true if user specify it explicit it,
|
||||
and will be false if user do not give this flag.
|
||||
SwitchArgument doesn't have constraint features,
|
||||
because it doesn't store any value inside.
|
||||
Thus no need to limit this.
|
||||
|
||||
\subsection arg_parser__argument__custom Custom Argument
|
||||
|
||||
In most cases, the combination use of argument presets and constraints is enough.
|
||||
However, if you still are urge to create your personal argument,
|
||||
please inherit AbstractArgument and implement essential class functions.
|
||||
For the class functions you need to implement,
|
||||
please refer to our argument presets.
|
||||
|
||||
\section arg_parser__argument_list Argument List
|
||||
|
||||
Argument list is a struct used by parser for parsing.
|
||||
It is a higher wrapper of a simple list containing argument items.
|
||||
We provide 2 ways to get argument list.
|
||||
|
||||
\li ArgumentList::CreateFromStd: Create argument list from standard C main function parameters.
|
||||
\li ArgumentList::CreateFromWin32: Create argument list from Win32 functions in Windows.
|
||||
You should use this function in Windows instead of ArgumentList::CreateFromStd.
|
||||
Because the command line passed in standard C main function has encoding issue in Windows.
|
||||
Use this function you will fetch correct argument list especially command including non-ASCII characters.
|
||||
|
||||
Please note the first argument in given command line will be stripped.
|
||||
Because in most cases it point to the executable self,
|
||||
and should not be seen as the part of argument list.
|
||||
|
||||
\section arg_parser__option_context Option Context
|
||||
|
||||
Please note any unknow argument will let the parser return false.
|
||||
This is different with other argument parsers.
|
||||
In other common argument parsers,
|
||||
they will collect all unknow argument as positional argument,
|
||||
or just simply ignore them.
|
||||
|
||||
OptionContext also will not add \c -h or \c --help switch automatically.
|
||||
This is also differnent with other parsers.
|
||||
You should manually add it.
|
||||
However, OptionContext provide a universal help print function, OptionContext::Help.
|
||||
You can directly call it to output help text if you needed (fail to parse or user order help).
|
||||
|
||||
\section arg_parser__limitation Limitation
|
||||
|
||||
This universal argument parser is a tiny parser.
|
||||
It only just fulfill my personal requirements.
|
||||
So it only accepts limited command line syntax.
|
||||
In following content I will tell you some syntaxes which this parser \b not accept.
|
||||
|
||||
\subsection arg_parser__limitation__flag_combination Flag Combination
|
||||
|
||||
\code{.sh}
|
||||
exec -l -s -h
|
||||
exec -lsh
|
||||
\endcode
|
||||
|
||||
Parser accept first line but not accept the second line.
|
||||
You must write these flags independently.
|
||||
|
||||
\subsection arg_parser__limitation__equal_symbol Equal Symbol
|
||||
|
||||
\code{.sh}
|
||||
exec --value 114514
|
||||
exec --value=114514
|
||||
exec --value:114514
|
||||
\endcode
|
||||
|
||||
Parser only accept first line command.
|
||||
You can not use equal symbol or any other symbol to assign value for specified argument.
|
||||
You must write value after the argument immediately please.
|
||||
|
||||
\subsection arg_parser__limitation__variable_argument Variable Argument
|
||||
|
||||
\code{.sh}
|
||||
exec -DSOME_VARABLE=SOME_VALUE
|
||||
exec -D SOME_VARIABLE=SOME_VALUE
|
||||
\endcode
|
||||
|
||||
Parser only accept second line.
|
||||
However you nned to write a custom argument or constraint to holding this value.
|
||||
|
||||
\subsection arg_parser__limitation__switch_dependency Switch Dependency
|
||||
|
||||
\code{.sh}
|
||||
exec --action-a --action-b
|
||||
\endcode
|
||||
|
||||
For command line written above,
|
||||
if you hope \c --action-a and \c --action-b is exclusive,
|
||||
or \c --action-b only be valid if \c --action-a specified,
|
||||
you should manually implement this.
|
||||
Parser don't have such features to process this switch dependency.
|
||||
|
||||
The thing you need to do is set these switches are \b not optional.
|
||||
And after parser do a success parsing,
|
||||
manually calling AbstractArgument::IsCaptured to fetch whether corresponding switches are captured,
|
||||
then do your personal dependency check.
|
||||
|
||||
*/
|
||||
}
|
||||
151
doc/src/carton/config_manager.dox
Normal file
151
doc/src/carton/config_manager.dox
Normal file
@@ -0,0 +1,151 @@
|
||||
namespace YYCC::ConfigManager {
|
||||
/**
|
||||
|
||||
\page config_manager Universal Config Manager
|
||||
|
||||
YYCC::ConfigManager 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::Constraints::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;
|
||||
};
|
||||
|
||||
// Initialize config manager
|
||||
TestConfigManager test;
|
||||
// Load settings.
|
||||
test.m_CoreManager.Load()
|
||||
// Get string setting 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 NumberSetting: The setting storing a number inside.
|
||||
It is a template class. Support all arithmetic and enum types (integral, floating point, bool, enum).
|
||||
\li 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 also can provide a constraint to setting.
|
||||
Constraint is the struct instructing library to limit value in specified range.
|
||||
It usually is used for making sure the setting stored value is valid.
|
||||
See \ref constraints chapters to know how we provide constraints.
|
||||
|
||||
\subsection config_manager__setting__custom Custom Setting
|
||||
|
||||
In most cases, the combination use of setting presets and constraints is enough.
|
||||
However, if you still are urge to create your personal setting,
|
||||
please inherit AbstractSetting and implement essential class functions.
|
||||
For the class functions you need to implement,
|
||||
please refer to our setting presets, NumberSetting and StringSetting.
|
||||
|
||||
\section config_manager__core_manager Core Manager
|
||||
|
||||
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 is important.
|
||||
It will be used when reading config file and only can be increased if needed (version can not downgrade).
|
||||
The last argument is an initializer list which contain the \b pointer to all settings this manager managed.
|
||||
|
||||
When executing YYCC::ConfigManager::CoreManager::Load to load configs, it will perform following steps one by one:
|
||||
|
||||
<UL>
|
||||
<LI>
|
||||
Open given config file.
|
||||
<UL>
|
||||
<LI>
|
||||
If given file is not existing, loading function will simply return and all configs will be reset to its default value.
|
||||
</LI>
|
||||
<LI>
|
||||
Success to open file, go to next step.
|
||||
</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI>
|
||||
Fetch version number from file.
|
||||
<UL>
|
||||
<LI>
|
||||
If fail to read version number from file, loading function will simply return and all configs will be reset to its default value.
|
||||
</LI>
|
||||
<LI>
|
||||
If the version of config file is higher than your specified version number when constructing this class,
|
||||
core manager will assume you are trying to read a config file created by a higher version program,
|
||||
and will reject reading and use default value for all settings.
|
||||
</LI>
|
||||
<LI>
|
||||
If the version of config file is lower than your specified version number,
|
||||
core manager will try to read config file and do proper migration (set default value for configs which do not existing) if possible.
|
||||
</LI>
|
||||
<LI>
|
||||
If the version of config file is equal than your specified version number,
|
||||
core manager will read config file normally.
|
||||
</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI>
|
||||
Read config file body.
|
||||
<UL>
|
||||
<LI>
|
||||
If any IO error occurs when reading, loading function will simply return.
|
||||
All read config will keep their read value and all configs which has not been read will keep their default value.
|
||||
</LI>
|
||||
<LI>
|
||||
If some config can not parse binary data to its type,
|
||||
this config will be skipped and core manager will process next config.
|
||||
This config will keep its default value.
|
||||
</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
All of these scenarios can be found by the return value of loading function.
|
||||
The return type of loading function, ConfigLoadResult is a flag enum.
|
||||
You can find whether loading process happend specified issue by using bitwise operation on it.
|
||||
|
||||
*/
|
||||
}
|
||||
181
doc/src/carton/console_helper.dox
Normal file
181
doc/src/carton/console_helper.dox
Normal file
@@ -0,0 +1,181 @@
|
||||
namespace YYCC::ConsoleHelper {
|
||||
/**
|
||||
|
||||
\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 #EnableColorfulConsole can fix this issue.
|
||||
|
||||
#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 \c \#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 #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.
|
||||
|
||||
*/
|
||||
}
|
||||
148
doc/src/carton/encoding_helper.dox
Normal file
148
doc/src/carton/encoding_helper.dox
Normal file
@@ -0,0 +1,148 @@
|
||||
namespace YYCC::EncodingHelper {
|
||||
/**
|
||||
|
||||
\page encoding_helper Encoding Helper
|
||||
|
||||
YYCC::EncodingHelper namespace include all encoding related functions:
|
||||
|
||||
\li The convertion between ordinary string and UTF8 string which has been introduced in chapter \ref library_encoding.
|
||||
\li Windows specific convertion between \c WCHAR, UTF8 string and string encoded by other encoding.
|
||||
\li The convertion among UTF8, UTF16 and UTF32.
|
||||
|
||||
\section encoding_helper__ordinary_utf8_conv Ordinary & UTF8 Convertion
|
||||
|
||||
These convertion functions have been introduced in previous page.
|
||||
See \ref library_encoding for more infomation.
|
||||
|
||||
YYCC supports following convertions:
|
||||
|
||||
\li #ToUTF8: Convert ordinary string to UTF8 string.
|
||||
\li #ToUTF8View: Same as ToUTF8, but return string view instead.
|
||||
\li #ToOrdinary: Convert UTF8 string to ordinary string.
|
||||
\li #ToOrdinaryView: Same as ToOrdinary, but return string view instead.
|
||||
|
||||
\section encoding_helper__win_conv Windows Specific Convertion
|
||||
|
||||
During Windows programming, the convertion between Microsoft specified \c wchar_t and \c char is an essential operation.
|
||||
Because Windows has 2 different function system, the functions ended with A and the functions ended with W.
|
||||
(Microsoft specified \c wchar_t is \c 2 bytes long. It's different with Linux defined common 4 bytes long).
|
||||
Thus YYCC provides these convertion functions in Windows to help programmer have better programming experience.
|
||||
|
||||
These functions are Windows specific, so they will be invisible in other platforms.
|
||||
Please use them carefully (make sure that you are using them only in Windows environment).
|
||||
|
||||
YYCC supports following convertions:
|
||||
|
||||
\li #WcharToChar: Convert \c wchar_t string to code page specified string.
|
||||
\li #CharToWchar: The reversed convertion of WcharToChar.
|
||||
\li #CharToChar: Convert string between 2 different code pages. It's a shortcut of calling CharToWchar and WcharToChar successively.
|
||||
\li #WcharToUTF8: Convert \c wchar_t string to UTF8 string.
|
||||
\li #UTF8ToWchar: The reversed convertion of WcharToUTF8.
|
||||
\li #CharToUTF8: Convert code page specified string to UTF8 string.
|
||||
\li #UTF8ToChar: The reversed convertion of CharToUTF8.
|
||||
|
||||
Code Page is a Windows concept.
|
||||
If you don't understand it, please view corresponding Microsoft documentation.
|
||||
|
||||
\section encoding_helper__utf_conv UTF8 UTF16 UTF32 Convertion
|
||||
|
||||
The convertion between UTF8, UTF16 and UTF32 is not common but essential.
|
||||
These convertions can be achieved by standard library functions and classes.
|
||||
(they are actually done by standard library functions in our implementation)
|
||||
But we provided functions are easy to use and have clear interface.
|
||||
|
||||
These functions are different with the functions introduced above.
|
||||
They can be used in any platform, not confined in Windows platforms.
|
||||
|
||||
YYCC supports following convertions:
|
||||
|
||||
\li #UTF8ToUTF16: Convert UTF8 string to UTF16 string.
|
||||
\li #UTF16ToUTF8: The reversed convertion of UTF8ToUTF16.
|
||||
\li #UTF8ToUTF32: Convert UTF8 string to UTF32 string.
|
||||
\li #UTF32ToUTF8: The reversed convertion of UTF8ToUTF32.
|
||||
|
||||
\section encoding_helper__overloads Function Overloads
|
||||
|
||||
Every encoding convertion functions (except the convertion between UTF8 and ordinary string) have 4 different overloads for different scenarios.
|
||||
Take #WcharToChar for example.
|
||||
There are following 4 overloads:
|
||||
|
||||
\code
|
||||
bool WcharToChar(const std::wstring_view& src, std::string& dst, UINT code_page);
|
||||
bool WcharToChar(const wchar_t* src, std::string& dst, UINT code_page);
|
||||
std::string WcharToChar(const std::wstring_view& src, UINT code_page);
|
||||
std::string WcharToChar(const wchar_t* src, UINT code_page);
|
||||
\endcode
|
||||
|
||||
\subsection encoding_helper__overloads_destination Destination String
|
||||
|
||||
According to the return value, these 4 overload can be divided into 2 types.
|
||||
The first type returns bool. The second type returns \c std::string instance.
|
||||
|
||||
For the first type, it always return bool to indicate whether the convertion is success.
|
||||
Due to this, the function must require an argument for holding the result string.
|
||||
So you can see the functions belonging to this type always require a reference to \c std::string in argument.
|
||||
|
||||
Oppositely, the second directly returns result by return value.
|
||||
It doesn't care the success of convertion and will return empty string if convertion failed.
|
||||
Programmer can more naturally use it because the retuen value itself is the result.
|
||||
There is no need to declare a variable before calling convertion function for holding result.
|
||||
|
||||
All in all, the first type overload should be used in strict scope.
|
||||
The success of convertion will massively affect the behavior of your following code.
|
||||
For example, the convertion code is delivered to some system function and it should not be empty and etc.
|
||||
The second type overload usually is used in lossen scenarios.
|
||||
For exmaple, this overload usually is used in console output because it usually doesn't matter.
|
||||
There is no risk even if the convertion failed (just output a blank string).
|
||||
|
||||
For the first type, please note that there is \b NO guarantee that the argument holding return value is not changed.
|
||||
Even the convertion is failed, the argument holding return value may still be changed by function itself.
|
||||
|
||||
In this case, the type of result is \c std::string because this is function required.
|
||||
In other functions, such as #WcharToUTF8, the type of result can be \c yycc_u8string or etc.
|
||||
So please note the type of result is decided by convertion function itself, not only \c std::string.
|
||||
|
||||
\subsection encoding_helper__overloads__source Source String
|
||||
|
||||
According to the way providing source string,
|
||||
these 4 overload also can be divided into 2 types.
|
||||
The first type take a reference to constant \c std::wstring_view.
|
||||
The second type take a pointer to constant \c wchar_t.
|
||||
|
||||
For first type, it will take the whole string for convertion, including \b embedded NUL terminal.
|
||||
Please note we use string view as argument.
|
||||
It is compatible with corresponding raw string pointer and string container.
|
||||
So it is safe to directly pass \c std::wstring for this function.
|
||||
|
||||
For second type, it will assume that you passed argument is a NUL terminated string and send it for convertion.
|
||||
|
||||
The result is clear.
|
||||
If you want to process string with \b embedded NUL terminal, please choose first type overload.
|
||||
Otherwise the second type overload is enough.
|
||||
|
||||
Same as destination string, the type of source is also decided by the convertion function itself.
|
||||
For exmaple, the type of source in #UTF8ToWchar is \c yycc_u8string_view and \c yycc_char8_t,
|
||||
not \c std::wstring and \c wchar_t.
|
||||
|
||||
\subsection encoding_helper__overloads__extra Extra Argument
|
||||
|
||||
There is an extra argument called \c code_page for #WcharToChar.
|
||||
It indicates the code page of destination string,
|
||||
because this function will convert \c wchar_t string to the string with specified code page encoding.
|
||||
|
||||
Some convertion functions have extra argument like this,
|
||||
because they need more infomations to decide what they need to do.
|
||||
Some convertion functions don't have extra argument.
|
||||
For exmaple, the convertion between \c wchar_t string and UTF8 string.
|
||||
Because both source string and destination string are concrete.
|
||||
There is no need to provide any more infomations.
|
||||
|
||||
\subsection encoding_helper__overloads__conclusion Conclusion
|
||||
|
||||
Mixing 2 types of source string and 2 types of destination string,
|
||||
we have 4 different overload as we illustrated before.
|
||||
Programmer can use them freely according to your requirements.
|
||||
And don't forget to provide extra argument if function required.
|
||||
|
||||
*/
|
||||
}
|
||||
110
doc/src/carton/exception_helper.dox
Normal file
110
doc/src/carton/exception_helper.dox
Normal file
@@ -0,0 +1,110 @@
|
||||
namespace YYCC::ExceptionHelper {
|
||||
/**
|
||||
|
||||
\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 #Register when program started or module loaded.
|
||||
And call #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.
|
||||
|
||||
Optionally, you can provide a function pointer during calling #Register as a callback.
|
||||
The prototype of this function pointer is #ExceptionCallback.
|
||||
This callback will be called if any unhandled exception happened.
|
||||
It provides 2 pathes to log file and core dump file respectively.
|
||||
So that you can use an explicit way, e.g. \c MessageBox, to tell user exception happened and where are the log files,
|
||||
especially in GUI application because the default output stream, \c stderr, is invisible in GUI application.
|
||||
|
||||
However, please note the pathes provided by callback may be empty.
|
||||
In this case, it means that handler fail to create corresponding log files.
|
||||
Also, if you trying to register unhandled exception handler on the same process in different module with different callback,
|
||||
only the callback provided in first success registering will be called when unhandled exception happened,
|
||||
due to \ref exception_helper__notes__singleton design.
|
||||
|
||||
\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 #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 #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 #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.
|
||||
|
||||
\subsection exception_helper__notes__user_callback The Timing of User Callback
|
||||
|
||||
The timing of calling user callback is the tail of unhandled exception handler.
|
||||
It means that all log and coredump have been written if possible before calling callback.
|
||||
Because user callback may still raise exception.
|
||||
We want all essential log files has been written before calling it,
|
||||
so that at least we can visit them on disk or console.
|
||||
|
||||
*/
|
||||
}
|
||||
Reference in New Issue
Block a user