I'm going to illustrate something that comes from a memory perhaps 30 years old, and I'm going to limit this to the scope of a suggestion, it will be up to you, @CosmimPerRam, to flesh this out.
I've referenced a few doc pages to be sure I'm heading in a reasonable direction. The last time I did this was in the very early 90's, when text based applications on UNIX, using actual TTY devices (AKA dumb terminals via RS232), was still a thing.
The objective, back then, was to execute another program, sending data to it as if that program received stdin keystrokes, and reading data back from that program's stdout.
The basic idea is to fashion a short, generic program which opens named pipes. The type of pipe you're using here are, as I recall, anonymous pipes. Named pipes appear as files in the file system (which is common to *NIX operation), but are not files themselves - the type of the entry is not a typical block storage (applicable to files), but of a pipe.
Your program launches this generic pipe substitution utility (which you write). It substitutes stdin and stdout (and perhaps stderr) to 2 (or 3 ) named pipes. Then, it uses execvp (or one from the family of functions) to run the program of interest, but now the stdin and stdout of that process has been tied to the named pipes, leaving the pipe substitutions intact.
Your application opens these 2 (or 3) named pipes to gain the kind of access you want.
First, look up the mkfifo function. An example is here: https://www.geeksforgeeks.org/named-pipe-fifo-example-c-program/
mkfifo creates a named pipe.
mkfifo( "PipeStdIn", 0666 );
mkfifo( "PipeStdOut", 0666 );
These are now two named pipes in a directory (the path can specify where).
Then, open the pipes with open....
int pipe_stdin = open( "PipeStdIn", O_WRONLY );
int pipe_stdout = open( "PipeStdOut", O_WRONLY );
This pipe can then be substituted for stdin or stdout using dup2 in the proposed generic utility
dup2( pipe_stdin, 0); // stdin is zero
dup2( pipe_stdout, 1); // stdout is 1 - stderr is 2
This proposed utility executes the program of interest (probably execvp), whatever that is, but that process's stdin and stdout have been tied to these named pipes.
Your application opens these two pipes using open, writing to one ( the pipe stdin), reading from the other (pipe stdout).
Good luck. I had this working, back in '91/'92, and it was used for at least 15 years when the *NIX box was, finally, replaced in that company.
I remember some tinkering was required, but alas I'm not building a working example to see what that was.