forked from cryfs/cryfs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIOStreamConsole.cpp
More file actions
113 lines (97 loc) · 3.48 KB
/
IOStreamConsole.cpp
File metadata and controls
113 lines (97 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "IOStreamConsole.h"
#include <boost/algorithm/string/trim.hpp>
#include "DontEchoStdinToStdoutRAII.h"
#include <cpp-utils/assert/assert.h>
using std::ostream;
using std::istream;
using std::string;
using std::vector;
using std::flush;
using std::function;
using boost::optional;
using boost::none;
namespace cpputils {
IOStreamConsole::IOStreamConsole(): IOStreamConsole(std::cout, std::cin) {
}
IOStreamConsole::IOStreamConsole(ostream &output, istream &input): _output(output), _input(input) {
}
optional<int> IOStreamConsole::_parseInt(const string &str) {
try {
string trimmed = str;
boost::algorithm::trim(trimmed);
int parsed = std::stoi(str);
if (std::to_string(parsed) != trimmed) {
return none;
}
return parsed;
} catch (const std::invalid_argument &e) {
return none;
} catch (const std::out_of_range &e) {
return none;
}
}
function<optional<unsigned int>(const string &input)> IOStreamConsole::_parseUIntWithMinMax(unsigned int min, unsigned int max) {
return [min, max] (const string &input) {
optional<int> parsed = _parseInt(input);
if (parsed == none) {
return optional<unsigned int>(none);
}
unsigned int value = static_cast<unsigned int>(*parsed);
if (value < min || value > max) {
return optional<unsigned int>(none);
}
return optional<unsigned int>(value);
};
}
template<typename Return>
Return IOStreamConsole::_askForChoice(const string &question, function<optional<Return> (const string&)> parse) {
optional<Return> choice = none;
do {
_output << question << flush;
string choiceStr;
getline(_input, choiceStr);
choice = parse(choiceStr);
} while(choice == none);
return *choice;
}
unsigned int IOStreamConsole::ask(const string &question, const vector<string> &options) {
if(options.size() == 0) {
throw std::invalid_argument("options should have at least one entry");
}
_output << question << "\n";
for (size_t i = 0; i < options.size(); ++i) {
_output << " [" << (i+1) << "] " << options[i] << "\n";
}
int choice = _askForChoice("Your choice [1-" + std::to_string(options.size()) + "]: ", _parseUIntWithMinMax(1, options.size()));
return choice-1;
}
function<optional<bool>(const string &input)> IOStreamConsole::_parseYesNo() {
return [] (const string &input) {
string trimmed = input;
boost::algorithm::trim(trimmed);
if(trimmed == "Y" || trimmed == "y" || trimmed == "Yes" || trimmed == "yes") {
return optional<bool>(true);
} else if (trimmed == "N" || trimmed == "n" || trimmed == "No" || trimmed == "no") {
return optional<bool>(false);
} else {
return optional<bool>(none);
}
};
}
bool IOStreamConsole::askYesNo(const string &question, bool /*defaultValue*/) {
_output << question << "\n";
return _askForChoice("Your choice [y/n]: ", _parseYesNo());
}
void IOStreamConsole::print(const string &output) {
_output << output << std::flush;
}
string IOStreamConsole::askPassword(const string &question) {
DontEchoStdinToStdoutRAII _stdin_input_is_hidden_as_long_as_this_is_in_scope;
_output << question << std::flush;
string result;
std::getline(_input, result);
_output << std::endl;
ASSERT(result.size() == 0 || result[result.size() - 1] != '\n', "Unexpected std::getline() behavior");
return result;
}
}