如何暂时将printf输出重定向到c-string?

时间:2010-04-01 18:34:20

标签: c postgresql redirect solaris printf

我正在编写一个分配,其中包括在Solaris机器上向PostgreSQL添加一些功能。作为转让的一部分,我们需要在客户端打印一些信息(即:使用elog。)

PostgreSQL已经有很多帮助方法可以打印出所需的信息,但是,帮助方法包含了数百个printf个调用,而elog方法只适用于c风格的字符串。

我是否可以暂时将printf次呼叫重定向到缓冲区,以便我可以轻松地通过elog将其发送到客户端?

如果那是不可能的,那么修改辅助方法以最终将缓冲区作为输出的最简单方法是什么?

4 个答案:

答案 0 :(得分:7)

如果您定义了自己的printf版本并将其链接到之前到libc版本,那么您的版本将取代标准版本。

您还应该能够通过使用LD_PRELOAD来加载已定义printf的库来取代标准版本。

要编写自己的printf,您需要使用stdarg功能:

int printf(const char *fmt, ...)
{
    int rv;
    va_list ap;
    va_start(ap, fmt);

    if (redirect_printf)
    {
#ifdef HAVE_VLOG
        // If you have a vlog function that takes a va_list
        vlog(fmt, ap);
        rv = ...;
#else
        char buffer[LARGESIZE];
        rv = vsnprintf(buffer, sizeof(buffer), fmt, ap);

        log(buffer);
#endif;
    }
    else
    {
        rv = vprintf(fmt, ap);
    }

    return rv;
}

当最终格式化输出大于LARGESIZE时,此简单版本将截断数据。如果你不想这样,你也可以先用NULL缓冲区调用vsnprintf来获得最终大小,进行动态分配,然后再调用vsprintf来格式化缓冲区。

答案 1 :(得分:4)

你错了 - elog支持格式字符串,就像printf一样。这是Postgres源代码的一个例子:

elog(DEBUG4, "TZ \"%s\" gets max score %d", tzname, i);

所以您只需要使用相同的参数在elog处添加printf

答案 2 :(得分:2)

最简单的方法是修改辅助方法以调用sprintf()。我不知道你是否可以轻易地破解它。也许

#define printf(...) sprintf(buffer, __VA_ARGS__)

会为你做的。您仍然需要为每个帮助函数定义buffer,并将其内容返回给关心它们的人。

答案 3 :(得分:1)

如果您可以容忍使用临时文件,则可以通过freopen()调用重定向标准: -

newstdout = freopen("/tmp/log", "w", stdout);

这将强制将所有printf写入/ tmp / log而不是控制台输出。在程序稍后的某个方便点,您可以打开相同的文件进行阅读: -

readfd = fopen("/tmp/log", "r");

并转发使用以下内容添加的内容: -

void forward_to_elog(void)
{
   int bytesread;
   char buf[100];

   memset(buf,0,100);
   do {
      memset(buf,0,100);
      bytesread = fread(buf, sizeof(buf)-1, 1, readfd);
      /* call elog(buf) */ ;
   } while(bytesread);

}

如果您打开文件,可以多次致电forward_to_elog()以逐步转发已添加的内容。

tmpnam()函数可用于获取临时文件的名称,如果您不想静态编码一个。