dst/source/patch/externalpipe.d
2025-06-26 13:47:07 -05:00

143 lines
4.1 KiB
D

module patch.externalpipe;
import core.sys.posix.signal : signal, SIGPIPE, SIG_IGN;
import core.sys.posix.unistd : pipe, fork, dup2, close, execvp, STDIN_FILENO, STDOUT_FILENO;
import core.stdc.stdio : fprintf, stderr, perror;
import core.stdc.stdlib : exit;
import st : Arg, term, Glyph, GlyphAttribute, UTF_SIZ, tlinelen, xwrite, utf8encode;
import patches : isPatchEnabled;
import std.algorithm : min;
static if (isPatchEnabled!"EXTERNALPIPEIN_PATCH") {
// csdfd is the slave fd of the pty
import st : csdfd;
}
static if (isPatchEnabled!"REFLOW_PATCH") {
// TLINE is defined in st module
import st : TLINE;
}
__gshared int extpipeactive = 0;
static if (isPatchEnabled!"EXTERNALPIPEIN_PATCH") {
void extpipe(const(Arg)* arg, int in_) {
int[2] to;
char[UTF_SIZ] buf;
extern(C) void function(int) nothrow @nogc oldsigpipe;
Glyph* bp, end;
int lastpos, n, newline;
if (pipe(to) == -1)
return;
switch (fork()) {
case -1:
close(to[0]);
close(to[1]);
return;
case 0:
dup2(to[0], STDIN_FILENO);
close(to[0]);
close(to[1]);
if (in_)
dup2(csdfd, STDOUT_FILENO);
close(csdfd);
execvp((cast(char**)arg.v)[0], cast(char**)arg.v);
fprintf(stderr, "st: execvp %s\n", (cast(char**)arg.v)[0]);
perror("failed");
exit(0);
default:
break;
}
close(to[0]);
// ignore sigpipe for now, in case child exists early
oldsigpipe = signal(SIGPIPE, SIG_IGN);
newline = 0;
for (n = 0; n < term.row; n++) {
bp = term.line[n];
lastpos = min(tlinelen(n) + 1, term.col) - 1;
if (lastpos < 0)
break;
end = &bp[lastpos + 1];
for (; bp < end; ++bp)
if (xwrite(to[1], buf.ptr, utf8encode(bp.u, buf.ptr)) < 0)
break;
if ((newline = term.line[n][lastpos].mode & GlyphAttribute.WRAP) != 0)
continue;
if (xwrite(to[1], "\n".ptr, 1) < 0)
break;
newline = 0;
}
if (newline)
xwrite(to[1], "\n".ptr, 1);
close(to[1]);
// restore
signal(SIGPIPE, oldsigpipe);
extpipeactive = 1;
}
void externalpipe(const(Arg)* arg) {
extpipe(arg, 0);
}
void externalpipein(const(Arg)* arg) {
extpipe(arg, 1);
}
} else {
void externalpipe(const(Arg)* arg) {
int[2] to;
char[UTF_SIZ] buf;
extern(C) void function(int) nothrow @nogc oldsigpipe;
Glyph* bp, end;
int lastpos, n, newline;
if (pipe(to) == -1)
return;
switch (fork()) {
case -1:
close(to[0]);
close(to[1]);
return;
case 0:
dup2(to[0], STDIN_FILENO);
close(to[0]);
close(to[1]);
execvp((cast(char**)arg.v)[0], cast(char**)arg.v);
fprintf(stderr, "st: execvp %s\n", (cast(char**)arg.v)[0]);
perror("failed");
exit(0);
default:
break;
}
close(to[0]);
// ignore sigpipe for now, in case child exists early
oldsigpipe = signal(SIGPIPE, SIG_IGN);
newline = 0;
for (n = 0; n < term.row; n++) {
bp = term.line[n];
lastpos = min(tlinelen(n) + 1, term.col) - 1;
if (lastpos < 0)
break;
end = &bp[lastpos + 1];
for (; bp < end; ++bp)
if (xwrite(to[1], buf.ptr, utf8encode(bp.u, buf.ptr)) < 0)
break;
if ((newline = term.line[n][lastpos].mode & GlyphAttribute.WRAP) != 0)
continue;
if (xwrite(to[1], "\n".ptr, 1) < 0)
break;
newline = 0;
}
if (newline)
xwrite(to[1], "\n".ptr, 1);
close(to[1]);
// restore
signal(SIGPIPE, oldsigpipe);
extpipeactive = 1;
}
}