简体   繁体   中英

Get Gnuplot version from pipe in C++

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);

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 (eg 5 in my case) and minvers contains the minor version (eg 0), with restvers being a suffix string (eg "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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM