简体   繁体   English

从C ++中的管道获取Gnuplot版本

[英]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. 在我的C ++程序(在Linux中)中,我可以打开一个管道来编写和设置Gnuplot程序的值。

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. 现在,我需要获取Gnuplot版本。 The show version command does this but how I can send this command and then read the value. show version命令可以执行此操作,但是如何发送此命令然后读取值。 Opening a pipe for reading seems to not work for me and the code stuck in the while loop without getting any data. 对于我来说,打开管道进行读取似乎不起作用,并且代码陷入了while循环而没有获取任何数据。

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: 由于在我的Debian / Linux / Sid / x86-64上,命令gnuplot --version输出到stdout的以下行:

 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). 之后, majvers包含gnuplot的主版本(例如,在我的情况下为5), minvers包含次版本(例如0), restvers部分为后缀字符串(例如, "patchlevel 1"不带引号)。

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"); 在这种罕见的情况下,在该popen和下一个pipe = popen("gnuplot", "w");之间更新gnuplot可能存在潜在的竞争条件pipe = popen("gnuplot", "w"); . BTW, naming a variable pipe is poor taste, since POSIX and Linux have the pipe(2) system call. 顺便说一句,由于POSIX和Linux具有pipe(2)系统调用,因此命名可变pipe的味道很差。 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"); 顺便说一句,您很可能要替换第二个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). 通过显式两次调用pipe(2) (后接适当的fork(2)execvp(3) ...)使输入和输出管道都到达gnuplot ,并在您自己的事件循环中对其进行管理(可能在poll( 2) ...看到这个那个答案)。

(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 ... ) (如果您的应用程序具有或使用其自己的事件循环,特别是如果它是Qt或GTK之上的GUI应用程序,则您希望对管道使用相同的事件循环;详细信息是提供该事件循环的库所特有的: g_spawn_async_with_pipesg_source_add_unix_fd用于GTK, QProcess用于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. 我没有时间详细说明如何执行此操作(将双管道插入命令+事件循环),但是Advanced Linux Programming本书(可在线获得)中有几章。 Be aware that you need some event loop. 请注意,您需要一些事件循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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