Reputation: 815
I am taking the input over from the Windows/Linux console such that the password that user types remain hidden as it happens in almost all Linux operating systems. How should I gracefully handle the exception thrown by the following snippet?
#ifdef _WIN32
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
std::string sTempPass;
getline(cin, sTempPass);
SetConsoleMode(hStdin, mode);
#elif __linux__
termios oldt;
tcgetattr(STDIN_FILENO, &oldt);
termios newt = oldt;
newt.c_lflag &= ~ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
std::string sTempPass;
getline(cin, sTempPass);
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
And what are the possible scenarios the above snippet can throw different types of exception and is there any other platform independent way to do this?
Upvotes: 0
Views: 147
Reputation: 51489
Rollback operations required in case of exceptions are usually implemented by means of running a destructor in C++. In your case you can create a class that stores the current state, and restores it in its destructor:
struct ConsoleMode {
DWORD mode;
HANDLE handle;
ConsoleMode(const HANDLE h) : handle(h) {
::GetConsoleMode(handle, &mode);
}
~ConsoleMode() {
::SetConsoleMode(handle, mode);
}
}
The calling code then simply constructs an object with automatic storage duration, and leaves cleanup to automatic stack unwinding:
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
{
ConsoleMode savedState(hStdin);
::SetConsoleMode(hStdin, savedState.mode & (~ENABLE_ECHO_INPUT));
std::string sTempPass;
getline(cin, sTempPass);
// savedState goes out of scope and runs its destructor to restore state.
// The destructor runs as part of stack unwinding in case of an exception as well.
}
The Linux implementation is analogous, with the respective system calls and members adjusted appropriately.
Upvotes: 1