143 lines
4.1 KiB
D
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;
|
|
}
|
|
} |