-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpreprocessor.hpp
More file actions
91 lines (76 loc) · 2.94 KB
/
preprocessor.hpp
File metadata and controls
91 lines (76 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#pragma once
#include <vector>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/wait.h>
std::string spawn_and_capture_stdout(const std::string& cmd, const std::vector<std::string>& args, const std::string& stdin_input) {
// Pipe 1: Used for STDOUT (Child writes, Parent reads)
int stdout_pipe[2];
// Pipe 2: Used for STDIN (Parent writes, Child reads)
int stdin_pipe[2];
if (pipe(stdout_pipe) == -1) {
perror("stdout pipe");
return "";
}
if (pipe(stdin_pipe) == -1) {
perror("stdin pipe");
// Clean up the first pipe before exiting
close(stdout_pipe[0]);
close(stdout_pipe[1]);
return "";
}
pid_t pid = fork();
if (pid == -1) {
perror("fork");
// Clean up both pipes before exiting
close(stdout_pipe[0]); close(stdout_pipe[1]);
close(stdin_pipe[0]); close(stdin_pipe[1]);
return "";
}
if (pid == 0) { // Child Process
// 1. Redirect STDOUT (capture output)
close(stdout_pipe[0]); // Close read end of stdout pipe
dup2(stdout_pipe[1], STDOUT_FILENO); // Duplicate write end to STDOUT
close(stdout_pipe[1]); // Close original write end
// 2. Redirect STDIN (receive input)
close(stdin_pipe[1]); // Close write end of stdin pipe
dup2(stdin_pipe[0], STDIN_FILENO); // Duplicate read end to STDIN
close(stdin_pipe[0]); // Close original read end
// Prepare arguments for execvp
std::vector<char*> c_args;
c_args.push_back(const_cast<char*>(cmd.c_str()));
for (const auto& arg : args) {
c_args.push_back(const_cast<char*>(arg.c_str()));
}
c_args.push_back(nullptr);
execvp(c_args[0], c_args.data());
// If execvp fails:
perror("execvp");
exit(1);
} else { // Parent Process
close(stdout_pipe[1]); // Parent won't write to child's stdout
close(stdin_pipe[0]); // Parent won't read from child's stdin
if (!stdin_input.empty()) {
if (write(stdin_pipe[1], stdin_input.c_str(), stdin_input.length()) == -1) {
perror("write to child stdin");
}
}
close(stdin_pipe[1]); // IMPORTANT: Close the write end to signal EOF to the child (g++ will unblock)
char buffer[4096]; // Increased buffer size for better performance
std::string result;
ssize_t bytes_read;
while ((bytes_read = read(stdout_pipe[0], buffer, sizeof(buffer))) > 0) {
result.append(buffer, bytes_read);
}
if (bytes_read == -1) {
perror("read from child stdout");
}
close(stdout_pipe[0]);
waitpid(pid, nullptr, 0);
return result;
}
}
std::string preprocess(const std::string& source_code) {
return spawn_and_capture_stdout("g++", { "-x", "c++", "-std=c++23", "-E", "-P", "-" }, source_code);
}