/**
 * Examples for getting user input from the console
 * Uses C99 dialect, so compile with -std=gnu99 or -std=c99
 * or via IDE-s Visual Studio 2013 (and higher) / DevC++5.7 (and higher)
 */
#include <stdlib.h>
#include <string.h> // strlen
#include <stdio.h>  // standard io
#include <conio.h>  // unbuffered io (on MSVC and MinGW compilers), also in lib ncurses on linux


/**
 * Never read more than specified maxCount bytes
 * Trim trailing newline after input
 * Return number of bytes read
 */



// get string from console using <stdio.h> (preferred portable way)
int cread_fgets(char* buffer, int maxCount)
{
	fgets(buffer, maxCount, stdin); // read up to maxCount chars from console
	fflush(stdin);                  // flush standard input (if some chars were left over)
	int size = strlen(buffer);      // get the length of the input string
	if (buffer[size - 1] == '\n') buffer[--size] = '\0'; // remove trailing \n
	return size;
}


// write one yourself, from K&R The C Programming Language:

/* getline:  read a line into str[max], return length  */
int getline(char str[], int max)
{
	int ch, len = 0, lim = max - 1;
	while (len < lim && (ch = getchar()) != '\n')
		str[len++] = ch;
	str[len] = '\0';
	if (len == lim) while (getchar() != '\n');
	return len;
}




#if _WIN32 // on MSVC and MinGW
	#if _MSC_VER // only on MSVC

		// get string from console using <conio.h> (on MSVC compiler)
		int cread_cgets_s(char* buffer, int maxCount)
		{
			size_t bytesRead;
			_cgets_s(buffer, maxCount, &bytesRead); // MS VC++, unbuffered
			// no trailing \n with cgets
			return bytesRead;
		}

	#endif


	#define WIN32_LEAN_AND_MEAN // only include the basic stuff
	#include <Windows.h>

	// get string from console using <Windows.h>
	int cread_winapi(char* buffer, int maxCount)
	{
		DWORD bytesRead;
		ReadConsoleA(GetStdHandle(STD_INPUT_HANDLE), buffer, maxCount, &bytesRead, 0);
		// remove trailing \r\n
		if (buffer[bytesRead - 1] == '\n') buffer[--bytesRead] = '\0';
		if (buffer[bytesRead - 1] == '\r') buffer[--bytesRead] = '\0';
		return bytesRead;
	}
#endif




/**
 * Reading a single character from console without text input
 * We're only interested in one character
 */


// getting ONLY a single character from console using <stdio.h>... NOT REALLY POSSIBLE
// scanf("%c"), fgetc, getc, getchar all act the same way and let the user enter text
// leaving any extra text into input buffer
char getchar_getc()
{
	char character = getc(stdin);
	fflush(stdin);
	return character;
}


#if _WIN32

	// getting ONLY a single character from console using <conio.h> - very easy
	// no character is printed to console
	char getchar_getch()
	{
		return _getch(); // or use _getche(); to also echo the char
	}


	// this is pretty much the same as _getch
	char getchar_winapi()
	{
		HANDLE STDIN = GetStdHandle(STD_INPUT_HANDLE);
		DWORD oldMode; 
		GetConsoleMode(STDIN, &oldMode); // get current input mode so we can restore it later
		SetConsoleMode(STDIN, 0);        // set console input mode to single character

		DWORD bytesRead; // read a single byte from STDIN:
		char character;
		ReadConsoleA(STDIN, &character, 1, &bytesRead, 0);

		SetConsoleMode(STDIN, oldMode); // restore old console mode
		return character;
	}


	// this one is special - only gets a keychar if a key was just down, otherwise returns 0
	char get_key_down()
	{
		return kbhit() == TRUE ? getch() : 0;
	}

#endif




int main(int argc, char** argv)
{
	int textLength;
	char text[80];
	char inputChar;
	
	// Reading via standard input (fully portable)
	printf("cread_fgets:  ");
	textLength = cread_fgets(text, sizeof text);
	printf("Input text:   %s\n", text);

#if _WIN32
	#if _MSC_VER
		// Reading via conio.h gets_s
		printf("cread_cgets:  ");
		textLength = cread_cgets_s(text, sizeof text);
		printf("Input text:   %s\n", text);
	#endif

	// Reading via Windows API
	printf("cread_winapi: ");
	textLength = cread_winapi(text, sizeof text);
	printf("Input text:   %s\n", text);
#endif

	printf("getchar_getc:   ");
	inputChar = getchar_getc();

#if _WIN32
	printf("getchar_getch:  ");
	inputChar = getchar_getch();
	printf("%c\n", inputChar); // nothing is displayed by getch, so we want a newline here

	printf("getchar_winapi: ");
	inputChar = getchar_winapi();
	printf("%c\n", inputChar);


	// an useful example combining stdio and conio:
	char username[80] = "";
	char password[80] = "";
	int  passLength   = 0;

	printf("Enter username: ");
	cread_fgets(username, sizeof username);
	printf("Enter password: "); // password needs to be hidden, so we use getch()
	while ((inputChar = _getch()) != '\r') {
		password[passLength++] = inputChar;
		putch('*'); // print * instead of input char; no backspace handling
	}
	password[passLength] = '\0';

	printf("\nInput was %s:%s\n", username, password);
#endif

	system("pause");
	return 0;
}