C++ Utilities  5.10.5
Useful C++ classes and routines such as argument parser, IO and conversion utilities
commandlineutils.cpp
Go to the documentation of this file.
1 #include "./commandlineutils.h"
3 
4 #include <iostream>
5 #include <string>
6 
7 #ifndef PLATFORM_WINDOWS
8 #include <sys/ioctl.h>
9 #include <unistd.h>
10 #else
11 #include <fcntl.h>
12 #include <windows.h>
13 #endif
14 
15 using namespace std;
16 
17 namespace CppUtilities {
18 
22 bool confirmPrompt(const char *message, Response defaultResponse)
23 {
24  cout << message;
25  cout << ' ' << '[';
26  cout << (defaultResponse == Response::Yes ? 'Y' : 'y');
27  cout << '/' << (defaultResponse == Response::No ? 'N' : 'n');
28  cout << ']' << ' ';
29  cout.flush();
30  for (string line;;) {
31  getline(cin, line);
32  if (line == "y" || line == "Y" || (defaultResponse == Response::Yes && line.empty())) {
33  return true;
34  } else if (line == "n" || line == "N" || (defaultResponse == Response::No && line.empty())) {
35  return false;
36  } else {
37  cout << "Please enter [y] or [n]: ";
38  cout.flush();
39  }
40  }
41 }
42 
48 {
49  TerminalSize size;
50 #ifndef PLATFORM_WINDOWS
51  ioctl(STDOUT_FILENO, TIOCGWINSZ, reinterpret_cast<winsize *>(&size));
52 #else
53  CONSOLE_SCREEN_BUFFER_INFO consoleBufferInfo;
54  if (const HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE)) {
55  GetConsoleScreenBufferInfo(stdHandle, &consoleBufferInfo);
56  if (consoleBufferInfo.dwSize.X > 0) {
57  size.columns = static_cast<unsigned short>(consoleBufferInfo.dwSize.X);
58  }
59  if (consoleBufferInfo.dwSize.Y > 0) {
60  size.rows = static_cast<unsigned short>(consoleBufferInfo.dwSize.Y);
61  }
62  }
63 #endif
64  return size;
65 }
66 
67 #ifdef PLATFORM_WINDOWS
72 void stopConsole()
73 {
74  fclose(stdout);
75  fclose(stdin);
76  fclose(stderr);
77  if (auto *const consoleWindow = GetConsoleWindow()) {
78  PostMessage(consoleWindow, WM_KEYUP, VK_RETURN, 0);
79  FreeConsole();
80  }
81 }
82 
98 void startConsole()
99 {
100  // attach to the parent process' console or allocate a new console if that's not possible
101  const auto consoleEnabled = isEnvVariableSet("ENABLE_CONSOLE");
102  if ((!consoleEnabled.has_value() || consoleEnabled.value()) && (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole())) {
103  // redirect stdout
104  auto stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_OUTPUT_HANDLE));
105  auto conHandle = _open_osfhandle(stdHandle, _O_TEXT);
106  auto fp = _fdopen(conHandle, "w");
107  *stdout = *fp;
108  setvbuf(stdout, nullptr, _IONBF, 0);
109  // redirect stdin
110  stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_INPUT_HANDLE));
111  conHandle = _open_osfhandle(stdHandle, _O_TEXT);
112  fp = _fdopen(conHandle, "r");
113  *stdin = *fp;
114  setvbuf(stdin, nullptr, _IONBF, 0);
115  // redirect stderr
116  stdHandle = reinterpret_cast<intptr_t>(GetStdHandle(STD_ERROR_HANDLE));
117  conHandle = _open_osfhandle(stdHandle, _O_TEXT);
118  fp = _fdopen(conHandle, "w");
119  *stderr = *fp;
120  setvbuf(stderr, nullptr, _IONBF, 0);
121  // sync
122  ios::sync_with_stdio(true);
123  // ensure the console prompt is shown again when app terminates
124  atexit(stopConsole);
125  }
126 
127  // set console character set to UTF-8
128  const auto utf8Enabled = isEnvVariableSet("ENABLE_CP_UTF8");
129  if (!utf8Enabled.has_value() || utf8Enabled.value()) {
130  SetConsoleCP(CP_UTF8);
131  SetConsoleOutputCP(CP_UTF8);
132  }
133 }
134 
139 pair<vector<unique_ptr<char[]>>, vector<char *>> convertArgsToUtf8()
140 {
141  pair<vector<unique_ptr<char[]>>, vector<char *>> res;
142  int argc;
143 
144  LPWSTR *argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
145  if (!argv_w || argc <= 0) {
146  return res;
147  }
148 
149  res.first.reserve(static_cast<size_t>(argc));
150  res.second.reserve(static_cast<size_t>(argc));
151  for (LPWSTR *i = argv_w, *end = argv_w + argc; i != end; ++i) {
152  int requiredSize = WideCharToMultiByte(CP_UTF8, 0, *i, -1, nullptr, 0, 0, 0);
153  if (requiredSize <= 0) {
154  break; // just stop on error
155  }
156 
157  auto argv = make_unique<char[]>(static_cast<size_t>(requiredSize));
158  requiredSize = WideCharToMultiByte(CP_UTF8, 0, *i, -1, argv.get(), requiredSize, 0, 0);
159  if (requiredSize <= 0) {
160  break;
161  }
162 
163  res.second.emplace_back(argv.get());
164  res.first.emplace_back(move(argv));
165  }
166 
167  LocalFree(argv_w);
168  return res;
169 }
170 #endif
171 
172 } // namespace CppUtilities
Contains all utilities provides by the c++utilities library.
CPP_UTILITIES_EXPORT TerminalSize determineTerminalSize()
Returns the current size of the terminal.
Response
The Response enum is used to specify the default response for the confirmPrompt() method.
CPP_UTILITIES_EXPORT bool confirmPrompt(const char *message, Response defaultResponse=Response::None)
Prompts for confirmation displaying the specified message.
std::optional< bool > isEnvVariableSet(const char *variableName)
Returns whether the specified env variable is set to a non-zero and non-white-space-only value.
The TerminalSize struct describes a terminal size.
unsigned short columns
number of columns
unsigned short rows
number of rows
constexpr int i