I'm trying to do something like echo {a:1} | prettier --stdin-filepath index.js
and return the value returned in stdout.
But I also want to make this program platform independant.
Referencing this and this, I managed to write code like this:
#include <Windows.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <stdexcept>
HANDLE hChildStd_IN_Rd = NULL;
HANDLE hChildStd_IN_Wr = NULL;
HANDLE hChildStd_OUT_Rd = NULL;
HANDLE hChildStd_OUT_Wr = NULL;
int main() {
const char source_code[] = "{a:1}";
FILE *fd_OUT = nullptr, *fd_IN = nullptr;
#ifdef _WIN32
try {
SECURITY_ATTRIBUTES saAttr{};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0))
throw std::runtime_error("StdoutRd CreatePipe");
if (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
throw std::runtime_error("Stdout SetHandleInformation");
if (!CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &saAttr, 0))
throw std::runtime_error("Stdin CreatePipe");
if (!SetHandleInformation(hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0))
throw std::runtime_error("Stdin SetHandleInformation");
TCHAR szCmdline[] = TEXT(
"C:\\Users\\yuto0214w\\AppData\\Roaming\\npm\\prettier.cmd "
"--stdin-filepath index.js");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStd_OUT_Wr;
siStartInfo.hStdOutput = hChildStd_OUT_Wr;
siStartInfo.hStdInput = hChildStd_IN_Rd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
if (!CreateProcess(NULL, szCmdline, NULL, NULL, TRUE, 0, NULL, NULL,
&siStartInfo, &piProcInfo))
throw std::runtime_error("CreateProcess");
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
CloseHandle(hChildStd_OUT_Wr);
CloseHandle(hChildStd_IN_Rd);
fd_OUT = _fdopen(_open_osfhandle((intptr_t)hChildStd_OUT_Rd, _O_RDONLY), "r");
fd_IN = _fdopen(_open_osfhandle((intptr_t)hChildStd_IN_Wr, _O_WRONLY), "w");
} catch (std::exception& e) {
std::cout << std::string("Encountered an error when running: ") + e.what()
<< std::endl;
return 1;
}
#else
// pipe fork dup2 execlp fdopen
#endif
fputs(source_code, fd_IN);
std::string formatted_code;
int c;
while ((c = fgetc(fd_OUT)) != EOF) {
formatted_code += c;
std::cout << "ch: " << c << std::endl; // For testing
}
fclose(fd_OUT);
fclose(fd_IN);
std::cout << formatted_code << std::endl;
return 0;
}
This will compile, but stops completely on fgetc
. I mean stops completely by it doesn't show any ch:
.
I built program using MSVC v143.
Thanks
The problem was I wasn't closing fd_IN
before reading fd_OUT
.
This causes deadlock because prettier is awaiting input from program, and program is awaiting output from prettier.
To fix this,
fputs(source_code, fd_IN);
fclose(fd_IN);
std::string formatted_code;
int c;
while ((c = fgetc(fd_OUT)) != EOF) {
formatted_code += c;
std::cout << "ch: " << c << std::endl; // For testing
}
fclose(fd_OUT);