I'm trying to make a password input mask function that's portable between windows, linux, and osx. So far I have code that works perfectly in linux and osx, but windows is giving me one issue.
Does anyone know why in windows fgetc requires me to press the enter
key twice before it exits the while loop?
static int get_password(char *password, int mask)
{
int max_pass_len = 512;
#ifdef _WIN32
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
DWORD prev_mode = 0;
GetConsoleMode(hstdin, &mode);
GetConsoleMode(hstdin, &prev_mode);
SetConsoleMode(hstdin, mode & ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT));
#else
static struct termios prev_terminal;
static struct termios terminal;
tcgetattr(STDIN_FILENO, &prev_terminal);
memcpy (&terminal, &prev_terminal, sizeof(struct termios));
terminal.c_lflag &= ~(ICANON | ECHO);
terminal.c_cc[VTIME] = 0;
terminal.c_cc[VMIN] = 1;
tcsetattr(STDIN_FILENO, TCSANOW, &terminal);
#endif
size_t idx = 0; /* index, number of chars in read */
int c = 0;
const char BACKSPACE = 8;
const char RETURN = 13;
/* read chars from fp, mask if valid char specified */
while (((c = fgetc(stdin)) != '\n' && c != RETURN && c != EOF && idx < max_pass_len - 1) ||
(idx == max_pass_len - 1 && c == 127))
{
if (c != 127 && c != BACKSPACE) {
if (31 < mask && mask < 127) /* valid ascii char */
fputc(mask, stdout);
password[idx++] = c;
} else if (idx > 0) { /* handle backspace (del) */
if (31 < mask && mask < 127) {
fputc(0x8, stdout);
fputc(' ', stdout);
fputc(0x8, stdout);
}
password[--idx] = 0;
}
}
password[idx] = 0; /* null-terminate */
// go back to the previous settings
#ifdef _WIN32
SetConsoleMode(hstdin, prev_mode);
#else
tcsetattr(STDIN_FILENO, TCSANOW, &prev_terminal);
#endif
return idx; /* number of chars in passwd */
}
```
Problem resolved using ReadConsole
#ifdef _WIN32
long unsigned int char_read = 0;
while ((ReadConsole(hstdin, &c, 1, &char_read, NULL) && c != '\n' && c != RETURN && c != EOF && idx < max_pass_len - 1) ||
(idx == max_pass_len - 1 && c == BACKSPACE))
#else
while (((c = fgetc(stdin)) != '\n' && c != EOF && idx < max_pass_len - 1) ||
(idx == max_pass_len - 1 && c == 127))
#endif