views:

52

answers:

3

Hey all, having a bit of a problem with a recent project. The goal here is to be able to input several lines of text containing a date in mm/dd/yyyy format followed by a whitespace and then a description of the event. I've accomplished actually allowing for multiple lines of text input (I think), but now I'm not exactly sure how to stop it. Is there a way to simply assume after a set amount of time, perhaps, that the user is done inputting? This problem is stressing me a lot as they never really addressed how to end user input, only how to accomplish multiple lines. We have to use the standard user input, not from text files which would be so much easier. Code below, please feel free to also tell me if I've made an unnoticed mistake elsewhere. I just need to be able to let the user finish the input so the program can re-order the events[] and output them.

calendar.cpp

#include <string>
#include <sstream>
#include <iostream>
#include <vector>

using namespace std;
#include "event.h"


int main(){
 // Maximum number of input lines
 const int MAX = 100; 

 // Array of pointers to events 
 Event *events[MAX];

 // Number of currently used pointers in events
 int size = 0;
 int i = 0;

 // Vector containing each input line as a string
 vector<string> vec (100);
 char temps[100];
 while(i < MAX){
  cin.getline(temps, 100);
  vec[i] = temps; 
  i++;
 }


 for(int i = 0; i < vec.size(); i ++){
   int found = vec[i].find("/");
   int tmo = atoi(vec[i].substr(0, found).c_str());
   int sfound = vec[i].find("/", found + 1, 6);
   int tda = atoi(vec[i].substr(found + 1, sfound - (found + 1)).c_str());
   int tye = atoi(vec[i].substr(sfound + 1, 4).c_str());
   string tdes = vec[i].substr(sfound + 6, vec[i].length() - (sfound + 6));
   events[size] = new Event(tmo, tda, tye, tdes);
   size++;
 }

 return 0;
}

event.cpp

#include <iostream>
#include <string>

using namespace std;
#include "event.h"

Event::Event(int mo, int da, int ye, string des){
 month = mo;
 day = da;
 year = ye;
 desc = des;
}

Event::~Event(){

}

void Event::print(){
 cout << month << "/" << day << "/" << year << " " << desc << endl;
}

event.h

#ifndef EVENT_H
#define EVENT_H

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

class Event{
 public:
  Event(int mo, int da, int ye, string des);
  ~Event();
  void print();
 private:
  int month;
  int day;
  int year;
  string desc;
};

#endif

Thank you in advance for your help, gentlemen.

EDIT:

Replacing my while() loop with:

while ((i < MAX) && (!cin.eof()) {
  cin.getline(temps, 100);
  vec[i] = temps; 
  i++;
 }

Seemed promising but even after injecting an EOF marker with Ctrl + D (^D) as suggested, user input can still continue. Any reason why this might be happening?

A: 

In general you need the user to type something that recognisably delimits their input. In mail, for example, the header is differentiated from the body by a blank line. You might think about requiring the user to have two blank lines, or some textual string such as "END" or "", or you might wait until you see another date that implicitly denotes the start of the next event.

If you really want timeouts... most OSes sport a select() function that can wait on the stdin file descriptor, and timeout if no read/exception events happen for a while. Alternatively, you can block reading and set a timer (e.g. alarm(2), setitimer() on Linux).

(As an aside, it's worth learning how to write streaming operators for your classes, but that's a big enough topic that I'm not going to dive into it here. You should also consider using push_back() to put lines of input into your vector, rather than creating it with many empty strings and blatting over them. That way, you don't have to use "100" and MAX, but can simply let things grow "naturally" as the input is handled.)

Tony
Thank you very much for the suggestion. Unfortunately I am unable to use a specified delimiter because these programs are tested using the Linux "diff" command and a set of pre-formated test files full of parameters. That select() function sounds interesting though, I'll read up on it.
DaveStance
A: 

You should give the user an escape character to cause the loop to exit.


//you should probably prompt the user.
 //some testing may be in order to determine the end of line sequence
 //could be \r\n or \n depending on OS, iirc
 string escape("**\r\n");
 const char * escape_ptr = escape.c_str();
 cout << "Please enter ** on one line to quit." << endl;
 vector<string> vec (100);
 char temps[100];
 while(i < MAX){
  cin.getline(temps, 100);
  vec[i] = temps;

  if (strncmp(temps,escape_ptr,4) == 0) {
     break; //the escape sequence was typed.
  }

  i++;
 }

0x90
+1  A: 

One way to accomplish this is to have the user press Ctrl-D to signify the End Of File. You will have to check for the end of file in your loop.

while ((i < MAX) && (!cin.eof()) {
  cin.getline(temps, 100);
  vec[i] = temps; 
  i++;
 }

This method has the additional benefit that a text file can be presented to the program instead of user input, and the same result will be achieved when the end of the file is reached.

EDIT:

Ctrl-Z is the EOF keystroke on Windows machines. The Ctrl-Z may have to be at the beginning of a line on that OS (see discussion at http://www.velocityreviews.com/forums/t356170-cant-detect-eof-from-stdin-on-windows-console.html for more on this topic)

levis501
This is precisely what I was looking for. Thank you very much for your help, I'll give this a shot!
DaveStance