Встроенный Perl в C, Perlapio - совместимость с STDIO
Я только что понял, что слой PerlIO, кажется, делает нечто большее, чем просто (более или менее) легко оборачивает stdio.h-функции. Если я пытаюсь использовать файл-дескриптор, разрешенный с помощью PerlIO_stdout()
а также PerlIO_fileno()
с функциями из stdio.h это не удается.
Например:
PerlIO* perlStdErr = PerlIO_stderr();
fdStdErrOriginal = PerlIO_fileno(perlStdErr);
relocatedStdErr = dup(fdStdOutOriginal);
_write(relocatedStdErr, "something", 8); //<-- this fails
Я пробовал это с VC10. Встроенная Perl-программа выполняется из другого контекста, поэтому невозможно использовать PerlIO из контекста, в котором выполняется запись в relocatedStdErr.
Для любопытных: мне нужно выполнить Perl-скрипт и перенаправить вывод stdout/stderr скрипта в журнал, сохраняя при этом возможность писать на stdout для себя. Кроме того, это должно работать независимо от платформы (Linux, консольное приложение Windows, настольное приложение Win32). Простая пересылка stdout/stderr не работает в настольных приложениях Win32, так как ее нет;) - вам нужно использовать stlout / stderr из perl.
Необходимое решение: уметь писать на файловом дескрипторе (или дескрипторе), производном от perlio, НЕ используя стек PerlIO.
РЕДАКТИРОВАТЬ - мое решение:
Когда Стори Теллер указывал на PerlIO_findFILE, это помогло. Итак, вот выдержка из кода - см. Комментарии внутри для описания:
FILE* stdErrFILE = PerlIO_findFILE(PerlIO_stderr()); //convert to Perl's 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's IO since win32subsystem(non-console) "_pipe" doesn't work
{
if (dup2(fdPipeStdErr[1], fdStdErrOriginal) >= 0) //hang pipe on stdErr - USE PERL's IO (since it's created by perl)
{
close(fdPipeStdErr[1]); //close the now duplicated writer on stdErr for further usage - USE PERL's IO (since it's created by perl)
//"StreamForwarder" creates a thread that catches/reads the pipe's 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 Stackru!", 20); //that works :)
Одна интересная вещь, которую я на самом деле не понимаю, это то, что документация Perl говорит, что не нужно #define PERLIO_NOT_STDIO 0
быть в состоянии использовать PerlIO_findFILE()
, Но для меня это прекрасно работает без него, и в дальнейшем мне все равно нравится использовать PerlIO и stdio вместе. Это пункт, который я не понял, что происходит.