views:

1008

answers:

5

Description:

  • Obtain output from an executable

Note:

  • Will not compile, due to fgets() declaration

Question:

  • What is the best alternative to fgets, as fgets requires char *?
  • Is there a better alternative?

Illustration:

void Q_analysis (const char *data)
{
string buffer;
size_t found;
found = buffer.find_first_of (*data);

FILE *condorData = _popen ("condor_q", "r");
while (fgets (buffer.c_str(), buffer.max_size(), condorData) != NULL)
{
 if (found == string::npos)
 {
  Sleep(2000);
 } else {
  break;
 }
}
return;
}
+3  A: 

You should be using the string.getline function for strings cppreference

however in your case, you should be using a char[] to read into.

eg

string s;
char buffer[ 4096 ];
fgets(buffer, sizeof( buffer ), condorData);
s.assign( buffer, strlen( buffer ));

or your code:

void Q_analysis( const char *data )
{
 char buffer[ 4096 ];

 FILE *condorData = _popen ("condor_q", "r");
 while( fgets( buffer, sizeof( buffer ), condorData ) != NULL )
 {
  if( strstr( buffer, data ) == NULL )
  {
    Sleep(2000);
  }
  else
  {
    break;
  }
 }
}
sfossen
Doesn't work with FILE *
anon
ya, I re-read the question and realized it was a pipe.
sfossen
+1  A: 

Instead of declaring you buffer as a string declare it as something like:

char buffer[MY_MAX_SIZE]

call fgets with that, and then build the string from the buffer if you need in that form instead of going the other way.

The reason what you're doing doesn't work is that you're getting a copy of the buffer contents as a c-style string, not a pointer into the gut of the buffer. It is, by design, read only.

-- MarkusQ

MarkusQ
A: 

You're right that you can't read directly into a std::string because its c_str and data methods both return const pointers. You could read into a std::vector<char> instead.

You could also use the getline function. But it requires an iostream object, not a C FILE pointer. You can get from one to the other, though, in a vendor-specific way. See "A Handy Guide To Handling Handles" for a diagram and some suggestions on how to get from one file type to another. Call fileno on your FILE* to get a numeric file descriptor, and then use fstream::attach to associate it with an fstream object. Then you can use getline.

Rob Kennedy
But note the vector <char> won't grow like I think the OP is expecting
anon
A: 

Try the boost library - I believe it has a function to create an fstream from a FILE*

or you could use fileno() to get a standard C file handle from the FILE, then use fstream::attach to attach a stream to that file. From there you can use getline(), etc. Something like this:

FILE *condorData = _popen ("condor_q", "r");
std::ifstream &stream = new std::ifstream();
stream.attach(_fileno(condorData));
Eric Petroelje
A: 

I haven't tested it all too well, but the below appears to do the job:

//! read a line of text from a FILE* to a std::string, returns false on 'no data'
bool stringfgets(FILE* fp, std::string& line)
{
  char buffer[1024];
  line.clear();

  do {
    if(!fgets(buffer, sizeof(buffer), fp))
      return !line.empty();

    line.append(buffer); 
  } while(!strchr(buffer, '\n'));
  return true;
}

Be aware however that this will happily read a 100G line of text, so care must be taken that this is not a DoS-vector from untrusted source files or sockets.

bert hubert