Built-in perl in C, perlapio - compatible with STDIO

I just realized that the PerlIO layer seems to be doing something more than just (more or less) easily transferring the functions of stdio.h. If I try to use the file descriptor allowed with PerlIO_stdout()and PerlIO_fileno()with functions from stdio.h, this will not work.

For instance:

PerlIO* perlStdErr = PerlIO_stderr();
fdStdErrOriginal = PerlIO_fileno(perlStdErr);
relocatedStdErr = dup(fdStdOutOriginal);
_write(relocatedStdErr, "something", 8); //<-- this fails

I tried this with VC10. The perl firmware is executed from a different context - therefore, it is not possible to use PerlIO from the context in which it writes to relocatedStdErr.

For the curious: I need to run a perl script and redirect the output of the stdout / stderr script to the log, while still being able to write to stdout for myself. In addition, this should work regardless of the platform (Linux, Windows console application, Win32 desktop application). Just forward stdout / stderr does not work in Win32 desktop applications, since they are not there;) - you need to use perl stdout / stderr.

Necessary solution: to be able to write to a file descriptor (or descriptor) obtained from perlio without using the PerlIO stack.

EDIT is my solution:

As the Teller narrator pointed to PerlIO_findFILE, this did the trick. So, here is an excerpt from the code - see comments inside for a description:

FILE* stdErrFILE = PerlIO_findFILE(PerlIO_stderr()); //convert to Perl stderr to stdio FILE handle

fdStdErrOriginal = _fileno(stdErrFILE); //get descriptor using MSVC

if (fdStdErrOriginal >= 0)
{
    relocatedStdErr = _dup(fdStdErrOriginal); //relocate stdErr for external writing using MSVC
    if (relocatedStdErr >= 0)
    {
        if (pipe(fdPipeStdErr) == 0) //create pipe for forwarding stdErr - USE PERL IO since win32subsystem(non-console) "_pipe" doesn't work
        {
            if (dup2(fdPipeStdErr[1], fdStdErrOriginal) >= 0) //hang pipe on stdErr - USE PERL IO (since it created by perl)
            {
                close(fdPipeStdErr[1]); //close the now duplicated writer on stdErr for further usage - USE PERL IO (since it created by perl)
                //"StreamForwarder" creates a thread that catches/reads the pipe input and forwards it to the processStdErrOutput function (using the PerlIO)
                stdErrForwarder = new StreamForwarder(fdPipeStdErr[0], &processStdErrOutput, PerlIO_stderr()); 
                return relocatedStdErr; //return the relocated stdErr to be able to '_write' onto it
            }
        }
    }
}
...
...
    _write(relocatedStdErr, "Hello Stackoverflow!", 20); //that works :)

, , , perl , #define PERLIO_NOT_STDIO 0 PerlIO_findFILE(). , PerlIO stdio. , , .

+4

Source: https://habr.com/ru/post/1666258/


All Articles