cpp-utilities/application/commandlineutils.cpp

135 lines
4.0 KiB
C++
Raw Normal View History

2015-09-06 20:19:09 +02:00
#include "./commandlineutils.h"
2015-06-24 00:44:16 +02:00
#include <iostream>
2017-05-01 03:13:11 +02:00
#include <string>
2015-06-24 00:44:16 +02:00
#ifdef PLATFORM_WINDOWS
2017-05-01 03:13:11 +02:00
#include <fcntl.h>
#include <windows.h>
#endif
2015-06-24 00:44:16 +02:00
using namespace std;
namespace ApplicationUtilities {
/*!
* \brief Prompts for confirmation displaying the specified \a message.
*/
2015-06-24 00:44:16 +02:00
bool confirmPrompt(const char *message, Response defaultResponse)
{
cout << message;
cout << ' ' << '[';
cout << (defaultResponse == Response::Yes ? 'Y' : 'y');
cout << '/' << (defaultResponse == Response::No ? 'N' : 'n');
cout << ']' << ' ';
cout.flush();
2017-05-01 03:13:11 +02:00
for (string line;;) {
2015-06-24 00:44:16 +02:00
getline(cin, line);
2017-05-01 03:13:11 +02:00
if (line == "y" || line == "Y" || (defaultResponse == Response::Yes && line.empty())) {
2015-06-24 00:44:16 +02:00
return true;
2017-05-01 03:13:11 +02:00
} else if (line == "n" || line == "N" || (defaultResponse == Response::No && line.empty())) {
2015-06-24 00:44:16 +02:00
return false;
} else {
cout << "Please enter [y] or [n]: ";
cout.flush();
}
}
}
2015-09-01 20:26:56 +02:00
#ifdef PLATFORM_WINDOWS
/*!
* \brief Closes stdout, stdin and stderr and stops the console.
* \remarks Interanlly used by startConsole() to close the console when the application exits.
*/
void stopConsole()
{
fclose(stdout);
fclose(stdin);
fclose(stderr);
2017-05-01 03:13:11 +02:00
if (auto *consoleWindow = GetConsoleWindow()) {
PostMessage(consoleWindow, WM_KEYUP, VK_RETURN, 0);
FreeConsole();
}
}
/*!
2016-12-24 16:08:09 +01:00
* \brief Starts the console and sets the console output code page to UTF-8 if this is configured.
* \remarks
* - only available under Windows
* - used to start a console from a GUI application
* - closes the console automatically when the application exists
*/
void startConsole()
{
2017-05-01 03:13:11 +02:00
if (!AttachConsole(ATTACH_PARENT_PROCESS) && !AllocConsole()) {
return;
}
// redirect stdout
auto stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE));
auto conHandle = _open_osfhandle(stdHandle, _O_TEXT);
auto fp = _fdopen(conHandle, "w");
*stdout = *fp;
setvbuf(stdout, NULL, _IONBF, 0);
// redirect stdin
stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE));
conHandle = _open_osfhandle(stdHandle, _O_TEXT);
fp = _fdopen(conHandle, "r");
*stdin = *fp;
setvbuf(stdin, NULL, _IONBF, 0);
// redirect stderr
stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE));
conHandle = _open_osfhandle(stdHandle, _O_TEXT);
fp = _fdopen(conHandle, "w");
*stderr = *fp;
setvbuf(stderr, NULL, _IONBF, 0);
2016-12-24 16:08:09 +01:00
#ifdef CPP_UTILITIES_FORCE_UTF8_CODEPAGE
// set console to handle UTF-8 IO correctly
2017-03-22 00:59:34 +01:00
// however, this doesn't work as intended and is therefore disabled by default
SetConsoleCP(CP_UTF8);
SetConsoleOutputCP(CP_UTF8);
2016-12-24 16:08:09 +01:00
#endif
// sync
ios::sync_with_stdio(true);
// ensure the console prompt is shown again when app terminates
atexit(stopConsole);
}
2016-12-18 17:19:57 +01:00
/*!
* \brief Convert command line arguments to UTF-8.
* \remarks Only available on Windows (on other platforms we can assume passed arguments are already UTF-8 encoded).
*/
2017-05-04 22:44:00 +02:00
pair<vector<unique_ptr<char[]>>, vector<char *>> convertArgsToUtf8()
2016-12-18 17:19:57 +01:00
{
2017-05-04 22:44:00 +02:00
pair<vector<unique_ptr<char[]>>, vector<char *>> res;
2016-12-18 17:19:57 +01:00
int argc;
LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
2017-05-01 03:13:11 +02:00
if (!argv_w || argc <= 0) {
2016-12-18 17:19:57 +01:00
return res;
}
res.first.reserve(static_cast<size_t>(argc));
res.second.reserve(static_cast<size_t>(argc));
2017-05-01 03:13:11 +02:00
for (LPWSTR *i = argv_w, *end = argv_w + argc; i != end; ++i) {
2017-03-22 00:59:34 +01:00
int requiredSize = WideCharToMultiByte(CP_UTF8, 0, *i, -1, nullptr, 0, 0, 0);
2017-05-01 03:13:11 +02:00
if (requiredSize <= 0) {
2016-12-18 17:19:57 +01:00
break; // just stop on error
}
auto argv = make_unique<char[]>(static_cast<size_t>(requiredSize));
2017-03-22 00:59:34 +01:00
requiredSize = WideCharToMultiByte(CP_UTF8, 0, *i, -1, argv.get(), requiredSize, 0, 0);
2017-05-01 03:13:11 +02:00
if (requiredSize <= 0) {
2016-12-18 17:19:57 +01:00
break;
}
res.second.emplace_back(argv.get());
res.first.emplace_back(move(argv));
}
LocalFree(argv_w);
return res;
}
2015-09-01 20:26:56 +02:00
#endif
2015-06-24 00:44:16 +02:00
} // namespace ApplicationUtilities