/* ignore.cpp - playing around reading from cin, using get (and put), 
                getline, putback, ignore, isspace, ws
 */

#include <iostream>
#include <string>
using namespace std;

string gettoken(void);

int main()
{
	// Assume c is a character, then it is more common to read
        // a character into c using "cin.get(c)" than "cin >> c".
	// Similarly for output we write "cout.put(c)" not "cout << c".
	
	// Read characters into a string until you get a carriage return
	string line;  // line is initially null, i.e. ""
	char c;
	cout << "Type up something: ";
	cin.get(c);
	while (c != '\n') {
		line +=c;
		cin.get(c);
	}
	cout << "You typed /" << line << "/\n"; // By the way, here is how we print "
	cout << "Yes, \"" << line << "\"\n";

	// A similar effect can be achieved with getline
	cout << "and now we see getline\n";
	const int LINESIZE = 128;
	char aline[LINESIZE+1];
	cin.getline(aline, LINESIZE, '\n');
	cout << "You typed \"" << aline << "\"\n";

	// Assume name is a string. Then when we say "cin >> name"
	// in name will be collected characters starting with the first
	// non-space character we type and ending with, and excluding,
	// the first space character after that.
	// [Space characters are ' ', '\n', '\t']
	
	// Consider the following:
	string name1, name2;
	cout << "Enter a name: ";
	cin >> name1;
	cout << "name1 = " << name1 << endl;
	cin >> name2;
	cout << "name2 = " << name2 << endl;
	// Notice that if you type at the prompt "joe doe",
	// I will print "name1 = joe" and "name2 = doe". In
	// other words what is not collected in name1 is
	// left there in the input buffer to be read in the next input
	// operation. If we do not like that we can do:
	string name3, name4;
	cout << "Enter a name: ";
	cin >> name3; 
	cin.ignore(128, '\n'); //Throw away up to 128 characters
			       //or until we skip '\n'
	cout << "name3 = " << name3 << endl;
	cin >> name4;
	cin.ignore(128, '\n'); 
	cout << "name4 = " << name4 << endl;
	// Now if we enter again "joe doe" we get "name3 = joe" and
	// the program will hang there waiting for input to be stored
	// in name4. It will wait until you type something non-space 
	// and press carriage return.

	// In a loop we want to read and print names until the
	// user just enters carriage return.
	// The following would not work
	/*
		for ( ; ; ) {
			string nom;
			cout << "Enter a name [CR to end]: ";
			cin >> nom;
			if (nom == "")break;
			cout << nom << endl;
		}
	 */
	// since if you just type CR the program hangs waiting for 
	// non-space characters. 
	// You can do the following:
	for ( ; ; ) {
		string nom;
		char c;

		cout << "Enter a name [CR to end]: ";
		do {
			cin.get(c);
			if (!isspace(c)) {
				cin.putback(c); // it undoes the effect of the last get
				cin >> nom;
				cin.ignore(128, '\n');
				cout << "the name was " << nom << endl;
				break;
			}
		} while (c != '\n');
	        if (nom == "") break;
	}
	cout << "Goodbye from first loop\n";

	// Alternatively you can use the gettoken function defined below.
	for ( ; ; ) {
		string nome;
		cout << "Enter a name [CR to end]: ";
		nome = gettoken();
		if (nome == "") break;
		cout << "The name was " << nome << endl;
	}
	cout << "Goodbye again\n";

	// Where ignore skipps all character up to a certain length, or 
	// until it encounters a termination character, ws is used
	// to skip exclusively spaces. For example here I will
	// collect character in a string skipping all spaces
	// until I get a total of 30 characters in the string.
	string xline;
	char d;
	cout << "We are collecting 30 non-space characters: ";
	while (xline.length() < 30) {
		cin >> ws;
		cin.get(d);	
		xline += d;
	}
	cout << "You collected: " << xline << endl;

	return 0;
}


// It returns an identifier from the current line (like if using '>>')
// and if no identifier is on the current line, returns "". If more than
// one identifier is on a line all but the first are discarded.
string gettoken(void)
{
  string token = "";     // Value returned to user.
  int gotnonspace = 0;  // It becomes 1 after we read a non-space character.
  for(;;){
      char c;
      cin.get(c);
      if (c == '\n')break;
      if (isspace(c)) {
	if (gotnonspace) 
	  {
	    cin.ignore(256, '\n');
	    break;
	  }
      }else{
	  gotnonspace = 1;
	  token += c;
	}
    }
  return token;
}

