在 C++ 中从管道获取 Gnuplot 版本
Get Gnuplot version from pipe in C++
在我的 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");
现在我需要获取 Gnuplot 版本。 show version
命令执行此操作,但我如何发送此命令然后读取值。打开管道进行读取似乎对我不起作用,代码卡在 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);
因为在我的 Debian/Linux/Sid/x86-64 上,命令 gnuplot --version
输出到 stdout
以下行:
gnuplot 5.0 patchlevel 1
我会简单地推荐
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;
之后,majvers
包含 gnuplot
的主要版本(例如在我的例子中为 5),minvers
包含次要版本(例如 0),restvers
是后缀字符串(例如 "patchlevel 1"
不带引号)。
在 gnuplot
在此 popen
和下一个 pipe = popen("gnuplot", "w");
之间更新的不寻常且不太可能的情况下,可能存在潜在的竞争条件。顺便说一句,将变量命名为 pipe
是一种糟糕的品味,因为 POSIX 和 Linux 具有 pipe(2) 系统调用。但我认为不值得关心竞争条件。
顺便说一句,您很可能想用显式 double 调用 pipe(2) 替换第二个 pipe = popen("gnuplot", "w");
(后跟适当的 fork(2) & execvp(3) ...) 将输入和输出管道都连接到 gnuplot
,并在您自己的 事件循环(可能在poll(2)附近……见this & that 答案)。
(如果您的应用程序有或使用自己的事件循环,特别是如果它是 Qt 或 GTK 之上的 GUI 应用程序,您希望对管道使用相同的事件循环;具体细节到提供该事件循环的库:g_spawn_async_with_pipes & g_source_add_unix_fd for GTK, QProcess for Qt ... )
我没有时间详细解释如何做到这一点(双管道进入命令 + 事件循环),但是 Advanced Linux Programming 书(在线提供)有几章介绍了这一点。请注意,您需要一些事件循环。
在我的 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");
现在我需要获取 Gnuplot 版本。 show version
命令执行此操作,但我如何发送此命令然后读取值。打开管道进行读取似乎对我不起作用,代码卡在 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);
因为在我的 Debian/Linux/Sid/x86-64 上,命令 gnuplot --version
输出到 stdout
以下行:
gnuplot 5.0 patchlevel 1
我会简单地推荐
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;
之后,majvers
包含 gnuplot
的主要版本(例如在我的例子中为 5),minvers
包含次要版本(例如 0),restvers
是后缀字符串(例如 "patchlevel 1"
不带引号)。
在 gnuplot
在此 popen
和下一个 pipe = popen("gnuplot", "w");
之间更新的不寻常且不太可能的情况下,可能存在潜在的竞争条件。顺便说一句,将变量命名为 pipe
是一种糟糕的品味,因为 POSIX 和 Linux 具有 pipe(2) 系统调用。但我认为不值得关心竞争条件。
顺便说一句,您很可能想用显式 double 调用 pipe(2) 替换第二个 pipe = popen("gnuplot", "w");
(后跟适当的 fork(2) & execvp(3) ...) 将输入和输出管道都连接到 gnuplot
,并在您自己的 事件循环(可能在poll(2)附近……见this & that 答案)。
(如果您的应用程序有或使用自己的事件循环,特别是如果它是 Qt 或 GTK 之上的 GUI 应用程序,您希望对管道使用相同的事件循环;具体细节到提供该事件循环的库:g_spawn_async_with_pipes & g_source_add_unix_fd for GTK, QProcess for Qt ... )
我没有时间详细解释如何做到这一点(双管道进入命令 + 事件循环),但是 Advanced Linux Programming 书(在线提供)有几章介绍了这一点。请注意,您需要一些事件循环。