Перенаправить стандартный вывод в ostream - PullRequest
0 голосов
/ 07 сентября 2018

Можно ли перенаправить stdout (НЕ cout!) в поток (ostream) (НЕ в файл!)

Почему? Я интегрирую интерпретатор Python в свое приложение и хочу захватывать print() вызовов из кода Python.

Я могу перенаправить cout таким образом, используя rdbuf(), но printf() или print() от python не перенаправляется, так как он идет на stdout, а не cout

1 Ответ

0 голосов
/ 07 сентября 2018

В Linux вы можете просто временно перенаправить STDOUT во временный файл на время сценария python.

В конце вызова python вы можете прочитать содержимое временного файла, а затем выгрузить файл.

Я почти уверен, что в Windows будет аналогичный механизм.

Вот первый шаг с попыткой некоего RAII очистить все ручки.

#include <unistd.h>
#include <cstdio>
#include <stdlib.h>
#include <string>
#include <iostream>

void simulate_python_script() {
    std::printf("Written to STDOUT I think");
}

struct auto_fd {
    auto_fd(int fd)
            : fd_(fd) {}

    ~auto_fd() {
        if (fd_ != -1)
            ::close(fd_);
    }
    auto_fd(auto_fd const&) = delete;
    auto_fd& operator=(auto_fd const&) = delete;

    operator int() const {
        return fd_;
    }

    int fd_;
};

struct file_closer
{
    void operator()(FILE* p) const noexcept
    {
        ::fclose(p);
    }
};


using auto_fp = std::unique_ptr<FILE, file_closer>;
auto make_auto_fp(FILE* fp)
{
    return auto_fp(fp, file_closer());
}

struct push_fd {
    push_fd(int target, int new_fd)
            : saved_(::dup(target)), target_(target) {
        ::dup2(new_fd, target);
    }

    ~push_fd() {
        if (saved_ != -1) {
            ::dup2(saved_, target_);
            ::close(saved_);
        }
    }

    int saved_, target_;
};

int main() {
    using namespace std::literals;


    auto tempfp = make_auto_fp(::tmpfile());
    auto tempfd = auto_fd(::fileno(tempfp.get()));

    // redirect STDOUT to the temp file with RAII
    {
        push_fd fd_save(1, tempfd);
        simulate_python_script();
    }

    // now read the file which Python thought was STDOUT    
    char buf[256];
    while (auto count = ::read(tempfd, buf, 256)) {
        if (count < 0) break; // error condition
        std::cout.write(buf, count);
    }

    std::cout << std::endl;
}
...