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; } }