0

In my C++ program (in linux), I can open a pipe for writing and set values for Gnuplot program.

FILE *pipe = NULL;

#ifdef WIN32
    pipe = _popen("pgnuplot -persist", "w");
#else
    pipe = popen("gnuplot", "w");
#endif

if(pipe == NULL)
    error("Could not open pipe for write!");

// set title name
fprintf(pipe, "set title 'Sample Points' \n");

Now I need to get the Gnuplot version. The show version command does this but how I can send this command and then read the value. Opening a pipe for reading seems to not work for me and the code stuck in the while loop without getting any data.

FILE* pipe = popen(command, "r");
if (!pipe)
{
    std::cout << "failed! (can not open pipe)" << endl;
    return;
}

char buffer[128];
std::string result = "";
while(!feof(pipe))
{
    if(fgets(buffer, 128, pipe) != NULL)
        result += buffer;
}
pclose(pipe);
ManiAm
  • 1,759
  • 5
  • 24
  • 43

1 Answers1

2

Since on my Debian/Linux/Sid/x86-64 the command gnuplot --version is outputting to stdout the following line:

 gnuplot 5.0 patchlevel 1

I would simply recommend

FILE* pipversion = popen("gnuplot --version", "r");
if (!pipversion) { perror("popen gnuplot"); exit(EXIT_FAILURE); };
char lineversion[128];
memset (lineversion, 0, sizeof(lineversion));
if (!fgets(lineversion, sizeof(lineversion), pipversion) { 
    perror("fgets"); exit(EXIT_FAILURE);
}
/// lineversion is like: gnuplot 5.0 patchlevel 1
int majvers=0, minvers=0, pos= -1;
char* restvers = NULL;
if (sscanf(lineversion, "gnuplot %d.%d %n", &majvers, &minvers, &pos) >= 2) {
  assert (pos>=0);
  restvers = lineversion+pos;
};
pclose(pipversion);
pipversion = NULL;

After that, majvers contains the major version of gnuplot (e.g. 5 in my case) and minvers contains the minor version (e.g. 0), with restvers being a suffix string (e.g. "patchlevel 1" without the quotes).

There might be a potential race condition in the unusual and unlikely case that gnuplot is updated between this popen and the next one pipe = popen("gnuplot", "w");. BTW, naming a variable pipe is poor taste, since POSIX and Linux have the pipe(2) system call. But I don't think it is worth caring about that race condition.

BTW, you very probably want to replace your second pipe = popen("gnuplot", "w"); with an explicit double invocation of pipe(2) (followed by appropriate fork(2) & execvp(3) ...) to have both input and output pipes to gnuplot, and manage them in your own event loop (probably around poll(2) ... see this & that answers).

(if you application has or uses its own event loop, in particular if it is a GUI application above Qt or GTK, you want to use the same event loop for the pipes; details are specific to the library providing that event loop: g_spawn_async_with_pipes & g_source_add_unix_fd for GTK, QProcess for Qt ... )

I don't have time to explain how to do that (double piping into command + event loop) in details, but the Advanced Linux Programming book (available online) has several chapters on that. Be aware that you need some event loop.

Community
  • 1
  • 1
Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547